当前位置: 首页 > news >正文

Vue 登录密码为什么要 RSA 加密?一文讲透前后端实现

Vue 前端 RSA 密码加密登录:从原理到落地

标签:Vue · 前端安全 · RSA · JSEncrypt · 登录鉴权
更新时间:2026-06-29


前言

做 Web 登录时,一个常见问题是:密码能不能明文传给后端?

答案当然是不行。即使用了 HTTPS,在浏览器到服务端这段链路里,仍有不少场景可能暴露敏感信息——抓包调试、日志打印、中间代理、XSS 脚本读取表单等。因此,很多团队会在前端对密码做RSA 非对称加密:浏览器只持有公钥,服务端持有私钥,密码以密文形式传输,降低泄露风险。

本文不绑定任何具体业务项目,只讲一套Vue + JSEncrypt + RSA的通用登录加密方案,可直接用于博客分享或新项目落地。


一、为什么选 RSA,而不是自己「发明」加密?

先明确一件事:RSA 不是用来替代 HTTPS 的,而是 HTTPS 之上的一层业务防护。

方案优点缺点
明文传输实现简单风险最高
前端 MD5/SHA看起来「加密了」可被重放,且哈希值本身可当密码用
AES 对称加密速度快密钥放前端等于公开
RSA 非对称加密公钥可公开,私钥只在服务端密文较长,不适合大数据

典型分工:

  • 前端:拿公钥,把用户输入的密码加密成 Base64 密文
  • 后端:拿私钥解密,得到明文后再做 BCrypt / Argon2 等哈希比对

这就是「锁和钥匙分离」:公钥相当于锁,谁都能锁;私钥相当于钥匙,只有服务端能开。


二、整体流程(一张图看懂)

后端服务请求层前端页面用户后端服务请求层前端页面用户输入账号 + 密码表单校验RSA 公钥加密密码提交登录参数POST /api/auth/loginRSA 私钥解密校验密码 + 签发 Token返回 Token 与用户信息持久化登录态登录成功跳转首页

一句话总结:用户看到的是明文密码,网络上传的是密文,数据库里存的是哈希。


三、技术选型

层级推荐方案
前端框架Vue 2 / Vue 3 均可
HTTPAxios / Fetch
加密库JSEncrypt
算法RSA-2048,PKCS#1 v1.5 填充
公钥存放环境变量或独立配置文件
私钥存放仅服务端,不进仓库、不进前端

安装依赖:

npminstalljsencrypt

四、前端实现(通用写法)

4.1 配置公钥

公钥建议放在环境变量中,便于不同环境切换:

# .env.development / .env.production VUE_APP_RSA_PUBLIC_KEY=你的RSA公钥Base64字符串

公钥可以公开;私钥绝不能出现在前端代码或环境变量里。

4.2 封装加密工具函数

importJSEncryptfrom'jsencrypt'/** * 使用 RSA 公钥加密明文 * @param {string} plainText - 待加密字符串(如密码) * @returns {string|null} Base64 密文,失败返回 null */exportfunctionrsaEncrypt(plainText){constpublicKey=process.env.VUE_APP_RSA_PUBLIC_KEYif(!publicKey||!plainText)returnnullconstencryptor=newJSEncrypt()encryptor.setPublicKey(publicKey)returnencryptor.encrypt(plainText)}

4.3 登录页调用示例

以下是完全独立的示例代码,展示「校验 → 加密 → 请求 → 存 Token」的标准写法:

import{rsaEncrypt}from'@/utils/rsaEncrypt'import{loginApi}from'@/api/auth'exportdefault{data(){return{form:{username:'',password:''},loading:false}},methods:{asynchandleLogin(){if(!this.form.username||!this.form.password){this.$message.warning('请输入账号和密码')return}constencryptedPwd=rsaEncrypt(this.form.password)if(!encryptedPwd){this.$message.error('密码加密失败,请稍后重试')return}this.loading=truetry{constres=awaitloginApi({username:this.form.username,password:encryptedPwd})// 保存 Token,跳转首页localStorage.setItem('token',res.data.token)this.$router.push('/')}finally{this.loading=false}}}}

4.4 请求体长什么样?

假设用户输入密码123456,前端发出的 JSON 大致如下:

{"username":"demo_user","password":"pY8Ve/JioBQFDjF++NzpHHREHoWp9s1CdZ/MixYlBb+..."}

其中password字段是RSA 加密后的 Base64 字符串,不是明文。

4.5 密文示例说明(明文:123456)

项目说明
明文123456
算法RSA-2048 / PKCS#1 v1.5
输出Base64 字符串

一个重要细节:RSA 使用 PKCS#1 填充时,同一明文每次加密结果可能不同(填充含随机数),但后端解密后都能得到相同的123456。所以 Postman 调试时,不要复制旧密文长期使用,应每次重新加密。

本地验证加密是否正常,可用 Node.js 内置crypto模块:

constcrypto=require('crypto')// 将 Base64 公钥转为 PEM 格式functiontoPem(base64Key){constlines=base64Key.match(/.{1,64}/g).join('\n')return`-----BEGIN PUBLIC KEY-----\n${lines}\n-----END PUBLIC KEY-----`}constpublicKeyBase64='你的公钥Base64字符串'constpem=toPem(publicKeyBase64)constcipher=crypto.publicEncrypt({key:pem,padding:crypto.constants.RSA_PKCS1_PADDING},Buffer.from('123456','utf8'))console.log(cipher.toString('base64'))

五、后端如何解密?

后端收到密文后,用RSA 私钥解密,得到明文密码,再进入常规鉴权流程。

5.1 Java(Spring Boot)

importjavax.crypto.Cipher;importjava.nio.charset.StandardCharsets;importjava.security.KeyFactory;importjava.security.PrivateKey;importjava.security.spec.PKCS8EncodedKeySpec;importjava.util.Base64;publicclassRsaDecryptUtil{// 私钥仅保存在服务端配置中心或密钥管理服务中privatestaticfinalStringPRIVATE_KEY_BASE64="你的私钥Base64字符串";publicstaticStringdecrypt(StringcipherTextBase64)throwsException{byte[]keyBytes=Base64.getDecoder().decode(PRIVATE_KEY_BASE64);PKCS8EncodedKeySpecspec=newPKCS8EncodedKeySpec(keyBytes);PrivateKeyprivateKey=KeyFactory.getInstance("RSA").generatePrivate(spec);Ciphercipher=Cipher.getInstance("RSA/ECB/PKCS1Padding");cipher.init(Cipher.DECRYPT_MODE,privateKey);byte[]plainBytes=cipher.doFinal(Base64.getDecoder().decode(cipherTextBase64));returnnewString(plainBytes,StandardCharsets.UTF_8);}}

Controller 中的典型用法:

@PostMapping("/api/auth/login")publicApiResultlogin(@RequestBodyLoginRequestreq)throwsException{StringplainPassword=RsaDecryptUtil.decrypt(req.getPassword());// plainPassword 此时为 "123456",再与数据库哈希比对returnauthService.login(req.getUsername(),plainPassword);}

5.2 C#(.NET 6+)

usingSystem.Security.Cryptography;usingSystem.Text;publicstaticclassRsaHelper{privateconststringPrivateKeyBase64="你的私钥Base64字符串";publicstaticstringDecrypt(stringcipherTextBase64){varrsa=RSA.Create();rsa.ImportPkcs8PrivateKey(Convert.FromBase64String(PrivateKeyBase64),out_);varcipherBytes=Convert.FromBase64String(cipherTextBase64);varplainBytes=rsa.Decrypt(cipherBytes,RSAEncryptionPadding.Pkcs1);returnEncoding.UTF8.GetString(plainBytes);// 例如 "123456"}}

5.3 后端加密(接口测试 / 第三方对接)

若需要在 Postman 或脚本里模拟前端加密:

stringRsaEncrypt(stringplainText,stringpublicKeyBase64){varrsa=RSA.Create();rsa.ImportSubjectPublicKeyInfo(Convert.FromBase64String(publicKeyBase64),out_);varbytes=rsa.Encrypt(Encoding.UTF8.GetBytes(plainText),RSAEncryptionPadding.Pkcs1);returnConvert.ToBase64String(bytes);}varencrypted=RsaEncrypt("123456",publicKey);

六、密钥怎么生成?

开发阶段可用 OpenSSL 快速生成一对 2048 位密钥:

# 生成私钥openssl genrsa-outprivate.pem2048# 从私钥导出公钥openssl rsa-inprivate.pem-pubout-outpublic.pem# 转为 PKCS#8 格式(Java 常用)openssl pkcs8-topk8-informPEM-outformPEM-nocrypt-inprivate.pem-outprivate_pkcs8.pem
  • 公钥→ 配置到前端环境变量
  • 私钥→ 配置到后端,权限最小化,禁止提交 Git

七、还有哪些场景可以用同一套方案?

只要涉及「敏感字符串从前端传到后端」,都可以复用同一公钥加密逻辑:

场景加密字段
用户登录password
修改密码oldPassword、newPassword、confirmPassword
重置密码newPassword
第三方凭证绑定secret、token 等短字符串

原则:短文本、低频传输适合 RSA;大段数据应改用 AES + RSA 混合加密或纯 HTTPS 传输。


八、踩坑清单(血泪经验)

1. 前后端填充方式不一致

JSEncrypt 默认 PKCS#1 v1.5,Java 需用RSA/ECB/PKCS1Padding,.NET 需用RSAEncryptionPadding.Pkcs1。填错一个字母,解密就是乱码。

2. 公钥私钥不是一对

前端换了公钥,后端没换私钥,或者开发/生产环境密钥混用,登录永远失败。建议密钥按环境隔离管理。

3. 以为密文可以复用

RSA 密文带随机填充,不能把 A 时刻的密文当作 B 时刻的密码用。自动化测试要每次动态加密。

4. 把 RSA 当万能盾

  • RSA 防不了 XSS(脚本仍能读输入框明文)
  • RSA 防不了重放(需配合 nonce、时间戳、HTTPS)
  • RSA 替代不了密码哈希存储

正确姿势:传输加密(RSA)+ 存储哈希(BCrypt)+ 传输通道(HTTPS),三层各司其职。

5. 私钥泄露

私钥一旦进 Git 历史,等于所有历史密文都可被离线解密。务必用.gitignore、密钥管理服务、CI 注入等方式隔离。


九、落地 Checklist

对接时可按此清单逐项核对:

  • 生成 RSA-2048 密钥对,公钥给前端,私钥给后端
  • 前端安装jsencrypt,封装rsaEncrypt工具函数
  • 登录接口传参前对密码字段加密
  • 后端登录接口先解密,再校验哈希
  • 前后端统一 PKCS#1 v1.5 填充
  • 生产环境启用 HTTPS
  • 私钥不进仓库、不进前端
  • Postman / 自动化测试支持动态加密

十、总结

Vue 登录密码 RSA 加密并不复杂,核心就四步:

  1. 前端用公钥把密码锁起来
  2. 网络上传输的是 Base64 密文
  3. 后端用私钥打开,得到明文
  4. 数据库只存哈希,不存明文

123456为例:用户输入的是123456,线上飞的是一长串 Base64,后端解出来还是123456,最后和库里 BCrypt 哈希比对——各司其职,清晰可控。

如果你正在设计登录模块,希望这篇能帮你少踩几个坑。欢迎收藏、转发,也欢迎在评论区交流你的实践经验。


延伸阅读

  • JSEncrypt 官方仓库
  • RFC 8017 - PKCS #1
  • OWASP 密码存储备忘单
http://www.cnnetsun.cn/news/3064378.html

相关文章:

  • JMeter TCP服务器压力测试实战:从协议解析到性能瓶颈定位
  • 老旧电视优化终极指南:MyTV-Android轻量级直播应用让安卓电视重获新生
  • 【实战】基于Altera FPGA与三速以太网IP核的MDIO配置与数据包接收调试全解析
  • 2026优质方矩管厂家甄选,全链精工生产赋能基建新能源工程建设
  • 【金蝶云星空】赠品业务对存货核算有什么影响?
  • SRA宏基因组数据提交实战:从Attribute填坑到Metadata避雷
  • 【实战解析】从零构建高精度果蔬识别模型:TensorFlow 2.3与MobileNet的融合应用
  • 华为OD机试2025C卷-IPv4地址转换成整数[100分](Java_Python3_C++_C语言_JsNode_Go)实现100%通过率
  • AXI协议——1.1. 从总线到接口:AXI协议全景解析
  • 华为OD机试2025C卷-不等式是否满足约束并输出最大差[100分](Java_Python3_C++_C语言_JsNode_Go)实现100%通过率
  • 上海GEO优化服务推荐:企业如何让品牌进入AI搜索答案?推荐了解 OurGEO
  • 现代前端的极致性能 icon 加载方案(死磕成功版)
  • 融完500亿!DeepSeek创始人又又又亲自下场,把AI推理提速85%还全开源
  • 【共创季稿事节】鸿蒙 ArkTS 布局进阶:layoutWeight 在嵌套布局中的传递与叠加
  • 破解Zotero Style插件版本兼容性难题:全面解决方案实战指南
  • 华为OD机试2025C卷-分苹果[100分](Java_Python3_C++_C语言_JsNode_Go)实现100%通过率
  • 网页端大模型应用安全渗透测试:从信息泄露到提示词注入的实战解析
  • MCMS v5.4.1文件上传漏洞深度剖析:从代码审计到RCE利用链实战
  • 一种确定性‑概率混合的语义模拟架构:非神经网络路径下的AI语言行为复现
  • 自然语言SEO:从关键词优化到意图匹配的系统升级
  • 解决 vLLM 启动报错,AMD 显卡常见的五个坑与填法
  • STM32L431 STOP2模式实战:从RTC唤醒到外设重配的完整流程
  • 3分钟告别成就焦虑:YaeAchievement原神数据导出神器全攻略
  • 从地面到空中:OHT天车系统的演进与核心技术解析
  • VisionTransformer(二)—— 从Word Embedding到Patch Embedding:跨模态的向量化统一
  • STM32F103C8T6 HAL库驱动DHT11:从CubeMX配置到OLED显示的实战解析
  • AIAgent交易系统压力测试:11项关键测试保障智能交易安全与合规
  • Gemini 3.5 能做什么?Agent工作流、编程开发和长上下文应用详解
  • Open CASCADE实战解析:构建与运用曲线曲面上的动态标架
  • 从下载到使用:Codex桌面版完整上手教程,用API中转解决登录难题(亲测有效)