常见的加密算法,例如DES等,都是可逆运算的算法,也就是说:如果能够获取到加密过程中的所有参数,就可以根据密文逆向运算得到原文!
在用户密码加密的领域,更希望使用的是不可逆运算的算法!这样的算法常见的有SHA(Secure Hash Algorithm)系列和MD(Message Digest)系列。
严格的说,SHA系列与MD系列的算法不是加密算法,它们归属“消息摘要算法”。
消算摘要算法的特点:
-
原文相同,摘要相同;
-
算法不变,摘要长度固定;
-
原文不同,摘要可能相同,但是,机率非常低!
为了避免md5加密后的密码被反查,在处理时,应该要求:
-
原始密码需要达到一定的安全强度(大小写字母、数字、符号)
-
加盐,盐值应该是较长的字符串
-
反复(多重)加密
-
使用位数更长的摘要算法
springboot带有一个DigestUtils工具类可以实现MD和SHA算法,即:
org.springframework.util.DigestUtils;
但是apache的功能更多,即:
org.apache.commons.codec.digest.DigestUtils;
添加commons-codec
依赖,可以使用Apache的DigetstUtils
,实现更多种摘要运算:
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
以下案例使用Apache的DigetstUtils进行:
@RunWith(SpringRunner.class)
@SpringBootTest
public class MessageDigestTestCase {
@Test
public void commonsEncrypt() {
String password = "123456";
String result = DigestUtils.sha512Hex(password);
//ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413
System.out.println("Length=" + result.length());
System.out.println(result);
}
@Test
public void encrypt() {
// 盐值
String salt = "苍老师昨天晚上跳的海草舞还是很不错的";
String password = "123456";
String src = salt + password + salt + password + salt;
String md5Password = DigestUtils.md5Hex(src);
System.out.println(md5Password);
}
}
例子:
需要完成密码加密的功能,本次加密使用了随机的盐,可以使用UUID作为随机盐。
UUID是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。通常平台会提供生成的API。按照开放软件基金会(OSF)制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字。
在Java中,通过java.util.UUID
类即可轻松获取到随机的UUID值:
String uuid = UUID.randomUUID().toString();
在UserServiceImpl
中添加加密方法:
/**
* 获取根据MD5加密的密码
* @param srcPassword 原密码
* @param salt 盐值
* @return 加密后的密码
*/
private String getMd5Password(String srcPassword, String salt) {
// 【注意】以下加密规则是自由设计的
// ----------------------------
// 使用盐值 + 原密码 + 盐值
String str = salt + srcPassword + salt;
// 循环执行10次摘要运算
for (int i = 0; i < 10; i++) {
str = DigestUtils.md5Hex(str);
}
// 返回摘要结果
return str;
}
然后,在reg()
方法中,在执行注册之前,先获取随机盐值,获取原始密码,执行加密,然后把盐值、加密后的密码封装回User对象中,再执行注册:
// 是:用户名不存在,允许注册,则处理密码加密
// 加密-1:获取随机的UUID作为盐值
String salt = UUID.randomUUID().toString();
// 加密-2:获取用户提交的原始密码
String srcPassword = user.getPassword();
// 加密-3:基于原始密码和盐值执行加密,获取通过MD5加密的密码
String md5Password = getMd5Password(srcPassword, salt);
// 加密-4:将加密后的密码封装在user对象中
user.setPassword(md5Password);
// 加密-5:将盐值封装在user对象中
user.setSalt(salt);
// 执行注册
addnew(user);