Java 实现密码添加随机盐进行 MD5 摘要加密(2021/05/11)
Java 实现密码添加随机盐进行 MD5 摘要加密(2021/05/11)
1. 概述
在日常开发中,经常面临用户密码的保存问题,一定不能明文存储密码到数据库,可以采用哈希摘要算法加密密码,再保存到数据库。
哈希摘要算法:只能从明文生成一个对应的哈希值,不能反过来根据哈希值得到对应的明文。
2. 环境准备
本文使用的所有生成摘要算法的方法都来自于 Hutool 工具包,Hutool 是一个小而全的 Java 工具类库,封装了一些静态方法,降低了相关 API 的学习成本,想要详细了解的话可以去阅读其官方文档。
笔者此处通过 Maven 的方式导入依赖:
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.6.5</version>
</dependency>
3. MD5 摘要算法
MD5 是一种非常经典的哈希摘要算法,被广泛应用于数据完整性的校验、数据摘要、数据加密等。
来看一个简单的例子,如下:
@Test
public void MD5Test() {
String password = "abc123456";
String md5 = DigestUtil.md5Hex(password);
System.out.println("md5 = " + md5);
}
运行结果:
md5 = 0659c7992e268962384eb17fafe88364
可以看到密码进行了摘要加密,已经无法直接获取明文密码,但是如果我们摘要结果输入到 MD5 免费破解网站,马上就能获取到原密码了。
想象一下,如果黑客构建一个超级大的数据库,把所有 20 位数字以内的数字和字母组合的密码全部计算 MD5 哈希值出来,并且把密码和它们对应的哈希值存到里面去(即彩虹表)。在破解密码的时候,只需要查一个这个彩虹表就完事了。所以单单 MD5 对密码取哈希值存储已经不安全了。
4. MD5 + 盐摘要算法
加盐:在密码学中,是指通过在密码任意固定位置插入特定的字符串,让散列后的结果和使用原始密码的散列结果不相符,这种过程称之为”加盐“。
用户密码 + 盐之后,进行哈希散列,再保存到数据库,这样可以有效应对彩虹表破解法,但是使用加盐,需要注意以下几点:
- 不能在代码中写死盐,且盐需要有一定的长度(盐写死太简单的话,黑客可能注册几个账号反推出来);
- 每一个密码都有独立的盐,并且盐要长一点,比如超过 20 位(盐太短,加上原始密码太短,容易破解);
- 最好是随机的值,并且是全球唯一的,意味着全球不可能有现成的彩虹表给你用;
此处笔者提供一种思路,对每一条用户密码生成唯一的 UUID 当作其盐值拼接在用户密码后边,然后对用户密码 + 盐进行 MD5 摘要加密,将加密后的哈希值与 UUID 通过一定的算法组合在一起存入数据库,便于在验证密码时能够从数据库中反解出 UUID。
具体实现代码如下:
import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.digest.DigestUtil;
/**
* 安全工具类.
*
* @author <a href="mailto:xiaoQQya@126.com">xiaoQQya</a>
* @version 1.0
* @date 2021/04/07
* @since 1.0
*/
public class SecureUtil {
private static final int PASSWORD_AND_SALT_LENGTH = 64;
/**
* 生成含有随机盐的密码.
*
* @param password 密码
* @return 含有随机盐的密码 MD5 值
* @author xiaoqqya
* @date 2021/04/07
*/
public static String generate(String password) {
String salt = IdUtil.simpleUUID();
password = DigestUtil.md5Hex(password + salt);
char[] md5 = new char[PASSWORD_AND_SALT_LENGTH];
for (int i = 0; i < PASSWORD_AND_SALT_LENGTH; i++) {
md5[i] = password.charAt(i / 2);
md5[++i] = salt.charAt(i / 2);
}
return new String(md5);
}
/**
* 校验密码是否正确.
*
* @param password 密码
* @param md5 带有随机盐的密码 MD5 值
* @return 密码是否正确
* @author xiaoqqya
* @date 2021/04/07
*/
public static boolean verify(String password, String md5) {
char[] pwd = new char[32];
char[] salt = new char[32];
for (int i = 0; i < PASSWORD_AND_SALT_LENGTH; i++) {
pwd[i / 2] = md5.charAt(i);
salt[i / 2] = md5.charAt(++i);
}
return DigestUtil.md5Hex(password + new String(salt)).equals(new String(pwd));
}
}
参考链接:
相关链接:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下