当前位置:   article > 正文

实现密码等明文的加密传输以及加密存储_前端加密后,后端不进行解密操作,而是再次加密后存入数据库

前端加密后,后端不进行解密操作,而是再次加密后存入数据库

需求:用户在登录时密码经常使用明文传输,在不安全的网络环境下,很容易造成密码泄露,而密码直接存储在数据库中,如果数据泄露,也会造成安全问题。

解决方法:前端给后端传输密码关键信息时,进行加密后再传输,后端解密验证,然后将密码加密后再存储到数据库中。

实现思路:

采用RSA非对称加密加密和解密密码传输,采用哈希加盐算法加密密码并存储

1.前端需要传输密码时,先向服务器获取一个加密公钥(加密密钥对由后端生成,以公钥为key,私钥为value存储在redis中)。

2.获取到公钥后,将密码进行加密,并将加密后的密码以及公钥一起传给后端。

3.后端根据公钥从redis中得到配对的密钥,然后对密码解密。

4.将密码加盐后进行哈希加密,然后把加密的盐和加密后的密码一起存入数据库。

5.下次比较时,只需要比较密码+盐进行hash计算后的值是不是和数据库的加密密码相同即可。

代码:

RSA加密与解密:

  1. package com.zong.zongmail.config;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.apache.tomcat.util.codec.binary.Base64;
  4. import org.springframework.stereotype.Repository;
  5. import javax.crypto.Cipher;
  6. import java.nio.charset.StandardCharsets;
  7. import java.security.*;
  8. import java.security.spec.PKCS8EncodedKeySpec;
  9. import java.util.HashMap;
  10. import java.util.Map;
  11. /**
  12. * @return
  13. * @Author: Zongmao on 2021/1/8 15:44
  14. * @description:非对称加密方法
  15. */
  16. @Slf4j
  17. @Repository
  18. public class RSAConfig {
  19. /**
  20. * @Author ZongMao
  21. * @Description //使用Java标准库提供的算法生成密钥对
  22. * @Date 2021/1/8 15:49
  23. **/
  24. public Map createKeyPair() throws GeneralSecurityException {
  25. // 生成公钥/私钥对:
  26. KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
  27. //它的密钥有256/512/1024/2048/4096等不同的长度。长度越长,密码强度越大,当然计算速度也越慢。
  28. //此处我设置256会报错:RSA keys must be at least 512 bits long
  29. kpGen.initialize(512);
  30. KeyPair kp = kpGen.generateKeyPair();
  31. PublicKey publicKey = kp.getPublic();
  32. PrivateKey privateKey = kp.getPrivate();
  33. //将公钥和私钥转换为base64编码便于存储和返回至前端
  34. byte[] publicKeyByte = publicKey.getEncoded();
  35. byte[] privateKeyByte = privateKey.getEncoded();
  36. String publicKeyStr = Base64.encodeBase64String(publicKeyByte);
  37. String privateKeyStr = Base64.encodeBase64String(privateKeyByte);
  38. Map map = new HashMap();
  39. map.put("publicKeyStr", publicKeyStr);
  40. map.put("privateKeyStr", privateKeyStr);
  41. return map;
  42. }
  43. /**
  44. * @Author ZongMao
  45. * @Description
  46. * 使用私钥解密(前端加密后传入的base64编码的信息,base64编码的私钥),
  47. * return 解密后的密码
  48. * @Date 2021/1/8 16:29
  49. **/
  50. public String decrypt(String passwordBase64, String privateKeyStr) throws GeneralSecurityException{
  51. Cipher cipher = Cipher.getInstance("RSA");
  52. //将Base64编码的私钥转为Private类型
  53. byte[] privateKeyByte = Base64.decodeBase64(privateKeyStr);
  54. KeyFactory kf = KeyFactory.getInstance("RSA"); // or "EC" or whatever
  55. PrivateKey privateKey = kf.generatePrivate(new PKCS8EncodedKeySpec(privateKeyByte));
  56. cipher.init(Cipher.DECRYPT_MODE, privateKey);
  57. //将base64编码的加密信息转为byte[]数据
  58. byte[] passwordByte = Base64.decodeBase64(passwordBase64);
  59. //获取解密后的byte[]数据
  60. byte[] resByte = cipher.doFinal(passwordByte);
  61. //将byte[]转为字符串,即为解密后的信息
  62. String resStr = new String(resByte, StandardCharsets.UTF_8);
  63. return resStr;
  64. }
  65. }

 哈希加盐加密以及验证方法:

  1. package com.zongmao.schoolsystem.config;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.springframework.stereotype.Repository;
  4. import java.io.UnsupportedEncodingException;
  5. import java.math.BigInteger;
  6. import java.security.MessageDigest;
  7. import java.security.NoSuchAlgorithmException;
  8. /**
  9. * @return
  10. * @Author: Zongmao on 2021/1/8 16:56
  11. * @description:使用Md5对明文口令进行加密(加盐)
  12. */
  13. @Slf4j
  14. @Repository
  15. public class HashConfigWithSalt {
  16. /**
  17. * @Author ZongMao
  18. * @Description //加盐进行hash加密
  19. * @Date 2021/1/8 16:56
  20. **/
  21. public String HashWithSalt(String message, String salt) throws NoSuchAlgorithmException, UnsupportedEncodingException {
  22. // 创建一个MessageDigest实例:
  23. MessageDigest md = MessageDigest.getInstance("MD5");
  24. // 反复调用update输入数据:
  25. String endMessage = message + salt;
  26. md.update(endMessage.getBytes("UTF-8"));
  27. byte[] result = md.digest();
  28. return new BigInteger(1, result).toString(16);
  29. }
  30. /**
  31. * @Author ZongMao
  32. * @Description //比较是否相等(加密后的字符串,盐,需要验证的信息)
  33. * @Date 2021/1/8 16:59
  34. **/
  35. public boolean isCommon(String mdStr, String salt, String message) throws UnsupportedEncodingException, NoSuchAlgorithmException {
  36. String nowStr = HashWithSalt(message, salt);
  37. if (nowStr.equals(mdStr)){
  38. return true;
  39. }
  40. return false;
  41. }
  42. }

 请求获取公钥:

  1. @PostMapping("/common/getPublicKey")
  2. public FormatResultData getPublicKey(){
  3. log.info("请求获取加密公钥");
  4. String publicKey = "";
  5. try {
  6. Map map = rsaConfig.createKeyPair();
  7. publicKey = (String) map.get("publicKeyStr");
  8. String privateKey = (String) map.get("privateKeyStr");
  9. //将publicKey作为key,privateKey作为value存入redis,并且设置过期时间
  10. stringRedisTemplate.opsForValue().set(publicKey, privateKey, 5 * 60 * 1000, TimeUnit.MILLISECONDS);
  11. }catch (GeneralSecurityException e){
  12. log.error(e.toString());
  13. return FormatResultData.error("获取公钥失败", 0);
  14. }catch (Exception e){
  15. log.info(e.toString());
  16. return FormatResultData.systemError();
  17. }
  18. return FormatResultData.success("获取公钥成功", publicKey);
  19. }

前端加密密码:

(使用jsencrypt)

  1. import {JSEncrypt} from 'jsencrypt'
  2. //加密
  3. export function encryptedData(publicKey, data) {
  4. let encryptor = new JSEncrypt();
  5. /*此处可以指定公钥的编码,也可以不指定*/
  6. encryptor.setPublicKey(publicKey, "base64");
  7. return encryptor.encrypt(data);
  8. }
  9. //解密
  10. export function decryptData(privateKey, data) {
  11. let decrypt = new JSEncrypt();
  12. decrypt.setPrivateKey(privateKey);
  13. return decrypt.decrypt(data);
  14. }
  15. //获取publicKey
  16. getPublicKey(){
  17. this.$http("/common/getPublicKey").then(res =>{
  18. if (res.code === 1){
  19. this.loginForm.publicKey = res.data;
  20. this.password = this.loginForm.password;
  21. this.loginForm.password = encryptedData(this.loginForm.publicKey, this.password);
  22. this.$http("/commonLogin/allUserLogin",this.loginForm).then(res =>{
  23. if (res.code === 1){
  24. this.Cookie.set("token", res.data, { expires: 1});
  25. this.$store.commit("changeUserType", this.loginForm.userType);
  26. localStorage.setItem("userName", res.extend);
  27. localStorage.setItem("account", this.loginForm.account);
  28. localStorage.setItem("userType", this.loginForm.userType);
  29. this.$router.push(this.fromPath);
  30. }else {
  31. this.loginForm.password = this.password;
  32. Message({
  33. message: res.msg,
  34. showClose: true,
  35. type:"error"
  36. });
  37. this.getCode();
  38. }
  39. }).catch(err =>{
  40. this.getCode();
  41. })
  42. }else {
  43. this.loginForm.publicKey = "";
  44. Message({
  45. message: "获取公钥失败,请稍后再试!",
  46. showClose: true,
  47. type:"error"
  48. });
  49. }
  50. }).catch(err =>{
  51. })
  52. },

注册新增账号时加密存储:

  1. /**
  2. * @Author ZongMao
  3. * @Description //新增管理员账号
  4. * @Date 2021/1/12 16:05
  5. **/
  6. @Override
  7. public String addAccount(AdminUser adminUser) throws Exception{
  8. String account = adminUser.getAccount();
  9. if (!account.equals("admin")){
  10. log.info("非法用户名!");
  11. throw new IllegalArgumentException("非法用户名");
  12. }
  13. QueryWrapper wrapper = new QueryWrapper();
  14. wrapper.eq("account", account);
  15. AdminUser hasUser = adminUserMapper.selectOne(wrapper);
  16. if (null != hasUser) {
  17. throw new IllegalArgumentException("管理员账号已存在");
  18. }
  19. String password = adminUser.getPassword(); //前端传的加密后的代码
  20. String publicKey = adminUser.getPublicKey(); //加密使用的公钥
  21. String privateKey = stringRedisTemplate.opsForValue().get(publicKey); //从redis中取出对应的密钥
  22. if (null == privateKey){
  23. throw new IllegalArgumentException("安全校验失败!");
  24. }
  25. String resPassword = rsaConfig.decrypt(password, privateKey); //使用密钥解密得到真实的密码
  26. String salt = randomConfig.randomData("", 6, false); //随机生成一个盐
  27. String hashPassword = hashConfigWithSalt.HashWithSalt(resPassword, salt); //把密码加盐后hash加密
  28. adminUser.setPassword(hashPassword); //把加密后的密码以及盐存入数据库
  29. adminUser.setSalt(salt);
  30. String id = UUID.randomUUID().toString();
  31. adminUser.setId(id);
  32. int addUser = adminUserMapper.insert(adminUser);
  33. if (addUser == 0){
  34. log.info("新增失败!");
  35. throw new IllegalArgumentException("新增失败!");
  36. }
  37. log.info("新增成功!");
  38. stringRedisTemplate.delete(publicKey);//新增成功后删除密钥对
  39. return "新增成功";
  40. }

 在登录情况下进行验证:

  1. /**
  2. * @Author ZongMao
  3. * @Description //登录(adminUser)
  4. * @Date 2021/1/12 11:57
  5. **/
  6. @Override
  7. public String login(String account, String password) throws Exception{
  8. QueryWrapper wrapper = new QueryWrapper();
  9. wrapper.eq("account", account);
  10. AdminUser adminUser = adminUserMapper.selectOne(wrapper); //从数据库中查出对应的用户
  11. if (null == adminUser){
  12. throw new IllegalArgumentException("账号不存在!");
  13. }
  14. Date lockTime = adminUser.getLockTime();
  15. if (null != lockTime){
  16. lockAccount.checkLock(lockTime);
  17. }
  18. String salt = adminUser.getSalt(); //从数据库中得到盐
  19. String okPassword = adminUser.getPassword(); //数据库中存储的加密的密码
  20. boolean okLogin = hashConfigWithSalt.isCommon(okPassword, salt, password); //比较是否相等,password已经是解密了的
  21. if (!okLogin){
  22. boolean needLock = lockAccount.lockTime(account);
  23. if (needLock){
  24. Date date = new Date();
  25. date.setTime(date.getTime() + needLockTime * 60 * 1000);
  26. adminUser.setLockTime(date);
  27. UpdateWrapper<AdminUser> updateWrapper = new UpdateWrapper<>();
  28. updateWrapper.eq("account", account)
  29. .set("lock_time", date);
  30. int i = adminUserMapper.update(adminUser, wrapper);
  31. if (i == 1){
  32. throw new IllegalArgumentException("你的账号已被锁定,请在" + needLockTime + "分钟后重试");
  33. }
  34. throw new IllegalArgumentException("你已多次尝试登录失败,账号可能会被锁定");
  35. }
  36. throw new IllegalArgumentException("账号或密码错误!");
  37. }
  38. String userId = adminUser.getId();
  39. String token = tokenConfig.createToken(userId);
  40. return token;
  41. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/948449
推荐阅读
相关标签
  

闽ICP备14008679号