1645087033(1).jpg

    流程图中左边为现有的登录,存在明文传输密码,通过抓包形式很容易破解,右图为RSA加密登录避免了密码明文传输,抓包获取不到真实密码,而且加密私钥一般在生成后五秒自动失效(自定义时间大小),破解难度大。
    密钥生成工具类如下

    1. package com.gaojin.common.utils;
    2. import org.apache.commons.codec.binary.Base64;
    3. import org.springframework.data.redis.core.RedisTemplate;
    4. import org.springframework.stereotype.Component;
    5. import javax.annotation.Resource;
    6. import javax.crypto.Cipher;
    7. import java.nio.charset.StandardCharsets;
    8. import java.security.*;
    9. import java.security.interfaces.RSAPrivateKey;
    10. import java.security.interfaces.RSAPublicKey;
    11. import java.security.spec.PKCS8EncodedKeySpec;
    12. import java.security.spec.X509EncodedKeySpec;
    13. import java.util.concurrent.TimeUnit;
    14. /**
    15. * @author zhouq
    16. * @date 2021/11/26
    17. */
    18. @Component
    19. public class RSAEncrypt {
    20. @Resource
    21. private RedisTemplate<String, Object> redisTemplate;
    22. // 自定义redis的key
    23. private static final String PREFIX = "gaojin-business:wmsPublicKey";
    24. /**
    25. * 随机生成密钥对
    26. *
    27. * @throws NoSuchAlgorithmException 异常
    28. */
    29. public String genKeyPair(String user) throws NoSuchAlgorithmException {
    30. // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
    31. KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
    32. // 初始化密钥对生成器,密钥大小为96-1024位
    33. keyPairGen.initialize(1024, new SecureRandom());
    34. // 生成一个密钥对,保存在keyPair中
    35. KeyPair keyPair = keyPairGen.generateKeyPair();
    36. // 得到私钥
    37. RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
    38. // 得到公钥
    39. RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
    40. String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
    41. // 得到私钥字符串
    42. String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
    43. redisTemplate.opsForValue().set(PREFIX + user, privateKeyString, 5, TimeUnit.SECONDS);
    44. return publicKeyString;
    45. }
    46. /**
    47. * RSA私钥解密
    48. *
    49. * @param str 加密字符串
    50. * @param privateKey 私钥
    51. * @return 铭文
    52. * @throws Exception 解密过程中的异常信息
    53. */
    54. public static String decrypt(String str, String privateKey) throws Exception {
    55. //64位解码加密后的字符串
    56. byte[] inputByte = Base64.decodeBase64(str.getBytes(StandardCharsets.UTF_8));
    57. //base64编码的私钥
    58. byte[] decoded = Base64.decodeBase64(privateKey);
    59. RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
    60. //RSA解密
    61. Cipher cipher = Cipher.getInstance("RSA");
    62. cipher.init(Cipher.DECRYPT_MODE, priKey);
    63. return new String(cipher.doFinal(inputByte));
    64. }
    65. }

    以下为登陆方法需要修改的地方

    1. @PostMapping("/login")
    2. public AjaxResult login(@RequestBody LoginBody loginBody) throws Exception {
    3. AjaxResult ajax = AjaxResult.success();
    4. // 获取redis中用户对应的私钥,对密码进行解密,
    5. String privateKey = (String) redisTemplate.opsForValue().get(PREFIX + loginBody.getUsername());
    6. // 对前端加密后的密码进行解密,获取到真实的密码
    7. String password = RSAEncrypt.decrypt(loginBody.getPassword(), privateKey);
    8. // 将真实的密码设置到登录参数中
    9. loginBody.setPassword(password);
    10. // 生成令牌
    11. String token = loginService.login(loginBody.getUserName(), loginBody.getPassword(),
    12. loginBody.getUuid());
    13. ajax.put(Constants.TOKEN, token);
    14. return ajax;
    15. }
    16. @GetMapping("/getPublicKey")
    17. public AjaxResult getPublicKey(String user) throws NoSuchAlgorithmException {
    18. return AjaxResult.success(rsaEncrypt.genKeyPair(user));
    19. }

    前端登录方法按照以下写法

    1. encryptedData(data, query) {
    2. var publicKey = query
    3. // 新建JSEncrypt对象
    4. const encryptor = new JSEncrypt()
    5. // 设置公钥
    6. encryptor.setPublicKey(publicKey)
    7. // 加密数据
    8. this.loginForm.password = encryptor.encrypt(data)
    9. },
    10. handleLogin() {
    11. this.$refs.loginForm.validate(valid => {
    12. if (valid) {
    13. this.loading = true
    14. if (this.loginForm.rememberMe) {
    15. Cookies.set('username', this.loginForm.username, { expires: 30 })
    16. Cookies.set('password', encrypt(this.loginForm.password), { expires: 30 })
    17. // Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 })
    18. } else {
    19. Cookies.remove('username')
    20. Cookies.remove('password')
    21. // Cookies.remove('rememberMe')
    22. }
    23. getPublicKey({ user: this.loginForm.username }).then(response => {
    24. console.log(response)
    25. this.encryptedData(this.loginForm.password, response.msg)
    26. this.$store.dispatch('Login', this.loginForm).then(() => {
    27. this.$router.push({ path: this.redirect || '/' }).catch(() => {})
    28. }).catch(() => {
    29. this.loading = false
    30. // this.getCode()
    31. })
    32. })
    33. }
    34. })
    35. }