- MD5加密
- 加盐加密
- 项目密码升级
MD5加密
MD5一系列公式进行复杂数学运算;特点:(用途校验和、计算hash值方式、加密)
1:定长;无论原始数据多长;算出的结果都是4或者8字节的版本。
2:冲突概率很小;就算你只改动一个地方;但是计算的结果相比之下是非常大
3:不可逆;正着计算很容易;逆着计算理论不可能实现;计算量很大;当前的条件是不可能实现
彩虹表:网上解密的工具只能把一些常见的字符串MD5值保存好;然后进行查表的值;并不是真实的计算出结果。
java中如何将一段这种字符串的password进行MD5加密呢:
DigestUtils.md5DigestAsHex是Apache Commons Codec库中的一个工具方法,用于计算传入参数的MD5哈希值,并返回一个16进制字符串表示的结果。
传入的参数需要是一个字节数(byte[])或字符串(String)。如果参数是字符串,则会自动将其转换为对应的字节数组。
String password="12345678";
String md5password=DigestUtils.md5DigestAsHex(password.getBytes());
System.out.println(md5password);
同一个字符串md5的值一个固定值;如果人家获取到你的md5这个值;破解密码随随便便;直接遍历彩虹表穷举;相当于加一把没带钥匙的锁
加盐加密
加密:密码+随机盐值 进行md5加密
解密:我们也没法解;因为是不可逆的;我们记住加密规则;再走一遍流程;对比用户登录的密码和数据库的是否一样
盐值:
我们得知道盐值是什么;才能重新再走一遍的规则;那就涉及盐值怎么来的;怎么储存
获取盐值:
String salt=UUID.randomUUID().toString().replace("-","");
//UUID一般被表示为32个字符的十六进制数,最常用的格式是8-4-4-4-12的五段分割
//例如:c4a760a8-dbcf-11e9-8f92-2b1af3aec0a6;我们把横杠去掉;替换成空字符串
你的盐值要每次不一样(每个用户的是不一样);那么就使用uuid;时间戳有可能重复。多个人的随机盐值是一样;会造成破解多个和破解一个是一样难度。
储存盐值:
方式1:盐值和密码单独存储两个字段(如果对方破解你数据库内容;那就很危险;相当于我告诉黑客;盐值是……;你自己去用彩虹表加密遍历一下和我的这个密码对比) 不现实
方式2:盐值和密码整合一起;存在一个字段。(用一个分隔符;分割哪里是盐值;哪里是MD5后的密码;给黑客破解增加难度;它还得猜你哪个是分隔符;那边是盐值;哪边是密码)
使用一个规则约定这里盐值和密码:分隔符(缺点;传递的正文不能有这个分隔符)?或者是按位数;前32位存盐值、后32位存密码。
为什么加盐值后破解成本大大提升:
假设我的盐值是1-n(实际更复杂);要暴力破解对应n个彩虹表;得拿盐值去和彩虹表的每一个进行MD5再和我们的密码对比。而且这样子破解的只是一个用户。
代码实现:
package com.example.demo.service;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import java.util.UUID;
public class salt_encrypt {
//加密过程;相当于注册的时候要用于存进去数据库的password字段
public static String encrypt(String reg_password){
String salt= UUID.randomUUID().toString().replace("-","");
String md5password= DigestUtils.md5DigestAsHex((reg_password+salt).getBytes());
String dbpassword=salt+"$"+md5password;
return dbpassword;
}
public static boolean decrypt(String login_password,String dbpassword){
boolean result=false;
//判空操作
if(StringUtils.hasLength(login_password)&&StringUtils.hasLength(dbpassword)){
//取出盐值
String [] dbpassword1=dbpassword.split("\\$");
// 因为 "$" 在正则表达式中具有特殊含义。在正则表达式中,"$" 表示行结束的位置,
// 如果不进行转义,正则表达式会将它解释为行结束符意思,而不是普通的字符 "$"。
String salt=dbpassword1[0];
String dbpassword2=dbpassword1[1];//获取我们直接用数据库的盐值+分隔符+md5密码是否包含这个要验证的密码md5值
login_password=DigestUtils.md5DigestAsHex((login_password+salt).getBytes());
if(dbpassword1.equals(login_password)){
result=true;
}
}
return result;
}
}
项目密码升级
代码改造:
UserController的注册;修改前
修改后:存的密码变成加盐md5后的
UserController的登录:修改前
修改后:
检查数据库password的字段是否是65位的;因为我们之前可能没使用加盐加密就没考虑那么多;如果我们之前随时password varchar(32)那么可以通过alter table userinfo modify column password varchar(65);进行修改
验证:
注册成功;且储存的密码样式是我们需要的。登录成功;说明验证是通过了。
Spring 框架提供了有加盐加密的方式,最常用的是Spring Security :
1:使用先添加Security框架
2:内置一个登录页面;我们得把这个关闭掉(因为我们自己有登录页面;不需要用它的)
它会在控制台提供一个密码给你
如何关闭:
在启动类添加这个(自动注入;关闭这个类自动的加载;但是APi还是能用的;因为我们把这个依赖加入项目了;;spring是真的默认是自动加载的)
使用: