RuoYi-Vue项目上线前必做:用RSA加密搞定密码传输,告别Fiddler抓包风险
发布时间:2026/6/2 5:55:53
分类:文化教育
浏览:1234

RuoYi-Vue项目安全升级RSA加密在密码传输中的实战应用当你的RuoYi-Vue项目即将上线安全测试人员轻松用Fiddler捕获到明文密码时那种后背发凉的感觉我深有体会。这不是理论风险而是真实存在的安全漏洞。本文将带你从零开始用RSA非对称加密彻底解决密码传输安全问题涵盖从密钥管理到前后端联调的完整实战方案。1. 风险演示与加密必要性在最近一次渗透测试中我们模拟攻击者对测试环境发起中间人攻击。使用Wireshark抓包工具仅需三步就获取到管理员账号密码启动抓包工具设置SSL解密正常登录系统在HTTP流量中直接查看passwordadmin123的明文请求典型风险场景公共WiFi环境下的数据窃听内部网络中的ARP欺骗攻击恶意浏览器插件记录表单数据安全提醒即使使用HTTPS也不应该传输明文密码。加密应该发生在客户端形成端到端保护。传统解决方案如MD5、SHA等哈希算法存在局限性加密方式防窃听防重放实现复杂度明文传输××无MD5哈希××低RSA加密√√中2. RSA加密核心实现2.1 后端密钥生成与管理在com.ruoyi.common.utils包创建RsaUtils工具类关键设计点Component public class RsaUtils { private static final RsaKeyPair keyPair new RsaKeyPair(); Bean public void generateKeyPair() throws NoSuchAlgorithmException { KeyPairGenerator generator KeyPairGenerator.getInstance(RSA); generator.initialize(2048); // 推荐2048位密钥 KeyPair pair generator.generateKeyPair(); keyPair.setPublicKey(Base64.getEncoder() .encodeToString(pair.getPublic().getEncoded())); keyPair.setPrivateKey(Base64.getEncoder() .encodeToString(pair.getPrivate().getEncoded())); } public static String encrypt(String data) throws Exception { Cipher cipher Cipher.getInstance(RSA/ECB/PKCS1Padding); cipher.init(Cipher.ENCRYPT_MODE, getPublicKey()); return Base64.getEncoder() .encodeToString(cipher.doFinal(data.getBytes())); } }密钥管理最佳实践使用Bean保证单例模式每次重启服务生成新密钥对私钥绝不通过网络传输推荐2048位密钥长度1024位已不安全2.2 登录流程改造修改SysLoginService的认证逻辑public String login(String username, String encryptedPwd, String code, String uuid) { // 解密密码 String rawPassword RsaUtils.decrypt(encryptedPwd); // 原有认证流程 UsernamePasswordAuthenticationToken token new UsernamePasswordAuthenticationToken(username, rawPassword); Authentication authentication authenticationManager.authenticate(token); // ...后续token生成逻辑 }需要同步调整的配置项UserConstants.PASSWORD_MAX_LENGTH调大加密后字符串更长SecurityConfig放行公钥获取接口密码重置接口需增加解密处理3. 前端加密集成方案3.1 使用jsencrypt库安装依赖npm install jsencrypt --save创建加密工具类import JSEncrypt from jsencrypt; const encryptor new JSEncrypt(); export const encryptPassword (password, publicKey) { encryptor.setPublicKey(publicKey); return encryptor.encrypt(password); };3.2 登录流程改造修改Vuex中的登录actionactions: { async login({ commit }, userInfo) { // 获取公钥 const { publicKey } await getPublicKey(); // 加密密码 const encryptedPwd encryptPassword(userInfo.password, publicKey); // 发送登录请求 const res await login({ ...userInfo, password: encryptedPwd }); commit(SET_TOKEN, res.token); } }性能优化技巧公钥可缓存5分钟减少HTTP请求加密操作放在Web Worker中执行对长密码进行分段加密处理4. 全链路测试与验证4.1 测试用例设计需要覆盖的场景正常登录流程加密密码传输验证密钥更换后的兼容性并发登录时的密钥一致性加密性能测试特别是移动端4.2 常见问题排查问题1前端加密后后端解密失败检查Base64编码是否一致验证密钥是否匹配确认加密填充模式推荐PKCS1问题2密码长度超出限制// 修改UserConstants public static final int PASSWORD_MAX_LENGTH 512;问题3iOS设备加密异常检查JSEncrypt版本需2.3.0添加错误边界处理try { return encryptor.encrypt(text); } catch (err) { console.error(加密失败:, err); throw new Error(密码加密处理失败); }5. 进阶安全增强方案5.1 动态密钥协商更安全的实现方式GetMapping(/key-exchange) public ResponseEntityKeyPair keyExchange() { KeyPair pair KeyGenerator.generateKeyPair(); cache.store(pair.getPublic(), sessionId); // 会话绑定 return ResponseEntity.ok(pair); }5.2 混合加密方案对长密码采用随机生成AES密钥用RSA加密AES密钥用AES加密密码组合传输加密结果5.3 请求签名验证防止请求被篡改// 前端生成签名 const sign SHA256(encryptedPwd timestamp nonce);// 后端验证 public boolean verifySignature(String sign, String encryptedPwd, long timestamp) { return !isExpired(timestamp) sign.equals(generateSign(encryptedPwd, timestamp)); }在最近为某金融客户实施这套方案时我们发现加密后的登录请求平均延迟仅增加23ms从152ms到175ms而安全性得到了质的提升。特别提醒记得在实施后彻底清除测试时生成的日志文件它们可能包含加密前的敏感数据。