详解Java MD5二次加密的应用

MD5二次加密的应用

  • 当前端传送密码到后端时候,需要进行两次MD5加密,登录和注册时的加解密流程是怎么样的?

前端和后端加密都可以规定使用密码的某几位作为盐进行加解密操作,而这种约定俗成的盐选取操作只有程序员自己知道,所以安全性较高,不需要前后端传送盐。 或者是前端和后端开发人员在开发的时候商量好这个第一层加密的盐,分别在前端和后端存储起来,这样前端在每次发送密码的时候都使用md5配合盐进行加密,服务器因为知道盐,所以可以自然的解密出来。

答:

  • 无论是注册还是登录,密码的第一次md5加密是在前端完成的,第二次加密都是在后端完成的,
  • 对每一个用户的密码进行两次md5加密会使用到两个salt,第一个salt是公共的(前后端共享),被final static修饰,第二个salt则是专门为每一个用户随机生成的,会存到数据库user表中的salt字段中(这是为了方便日后登录时进行密码验证操作)。
  • 再次强调 MD5 只是哈希,而不是加密。MD5 是没有可能解密的,因为一个 MD5 可能对应无数种可能的明文。

当用户第一次注册时

  • 前端先使用全局公共的salt1将inputPass(用户输入的密码)先转换成fromPass(过渡密码),随后传给服务器,
  • 服务器随机生成一个用户专属的salt2,使用md5和salt2将fromPass转换成dbPass(存储在数据库中的密码),
  • 转换结束后,会将用户的注册信息(包含用户名和经过二次加密后的密码)以及专属salt2存到数据库中。

当用户使用用户名和密码进行登录时

  • 前端会先使用公共的salt1对inpuPass进行第一次加密,得到fromPass并且传给服务器,
  • 服务器根据用户名查找到其对应的专属salt2和password(用户首次注册时二次加密后的密码),利用这个salt2对用户的已经被公共盐加密过的密码进行二次加密,
  • 与数据库中取出的密码进行比较,若一致,则登录成功,否则登录失败。

如果从对数据库中取出来的密码进行一层解密(即将密码第二次加密后的状态还原为第一次加密后的状态),为什么验证密码的时候,不是直接将这个解密后的密码同前端传过来的被加密后的密码进行比较,从而得出密码是否正确?

答:因为md5是利用hash进行加密的,这是一个不可逆的过程,即使知道hash的结果但是反向推导出hash函数的输入参数几乎是不可能的,所以。

以下是服务端实现两次md5加密的方法,inputPassToFromPass和inputPassToDBPass方法仅仅用于测试,在真实的业务场景中,前端传过来密码的永远不可能是明文密码,一定是经过inputPassToFromPass()方法加密后的密码

import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;

import java.nio.charset.StandardCharsets;

/**
 * MD5工具类
 */
@Component
public class MD5Util {
    public static String md5(String str) {
        return DigestUtils.md5DigestAsHex(str.getBytes(StandardCharsets.UTF_8));
    }

    private static final String salt = "1a2b3c4d";

    /**
     * 第一次加密
     **/
    public static String inputPassToFromPass(String inputPass) {
        // salt可以随机的放在输入密码的各个部分当中
        String str = salt.charAt(0) + salt.charAt(2) + inputPass + salt.charAt(5) + salt.charAt(4);
        return md5(str);
    }

    /**
     * 第二次加密, 使用的盐需要重新生成(这个盐会存放到数据库中,成为用户的一个属性),
     **/
    public static String formPassToDBPass(String formPass, String salt) {
        String str = salt.charAt(0) + salt.charAt(2) + formPass + salt.charAt(5) + salt.charAt(4);
        return md5(str);
    }

    /**
     * 将第一次加密和第二次加密调用
     */
    public static String inputPassToDBPass(String inputPass, String salt) {
        String fromPass = inputPassToFromPass(inputPass);
        String dbPass = formPassToDBPass(fromPass, salt);
        return dbPass;
    }

    public static void main(String[] args) {
        System.out.println(inputPassToFromPass("123456"));
        System.out.println(formPassToDBPass(inputPassToFromPass("123456"), "abcdefgh"));
        System.out.println(inputPassToDBPass("123456", "abcdefgh"));
    }
}

原文地址:https://juejin.cn/post/7199812069050630204