目录
前言:
一、密码加密
1. MD5介绍
2.彩虹表攻击
3.测试复杂密码是否能被攻破
二、加盐算法
1.对密码123456演示加盐算法
2.盐值的储存
3.密码加盐思想总结
三、Java代码实现
前言:
早些年,数据泄露屡见不鲜,每个班上总有一两个人qq被盗然后群发信息...这是因为,在以前,我们的密码在数据库里都是明文储存。
以前黑客看到的:账号:123456 密码:123456
黑客:
而现在,我们的密码在数据库里都是密文储存,黑客破解难度大大增加。
现在黑客看到的:账号:123456 密码:e10adc3949ba59abbe56e057f20f883e
一、密码加密
这一串复杂字符其实就是“123456”通过md5加密得到的。
md5加密网站
1. MD5介绍
MD5是一种摘要算法, 摘要算法是一种将任意长度的输入数据转换为固定长度的哈希值的算法。这个哈希值可以视为输入数据的“指纹”,因为它能够唯一地表示原始数据。
主要特点包括:
固定长度输出:无论输入数据的长度是多少,摘要算法都会生成一个固定长度的哈希值。比如,MD5 总是生成 128 位(16 字节)的哈希值,而 SHA-256 总是生成 256 位(32 字节)的哈希值。
不可逆性:摘要算法是单向的,意味着从生成的哈希值无法反向推导出原始数据。
高敏感性:即使输入数据的改变非常微小(比如仅改变一个字符),生成的哈希值也会有很大的不同。
抗碰撞性:不同的输入数据不应生成相同的哈希值。然而,在理论上可能存在哈希碰撞(即两个不同的输入数据生成相同的哈希值),但好的摘要算法会使这种碰撞非常难以发生。
2.彩虹表攻击
黑客无法直接从e10adc3949ba59abbe56e057f20f883e看出或计算出这个是“123456”。
最怕黑客动脑子...
黑客可以猜你的密码可能是123456,看看出来的值是否与e10adc3949ba59abbe56e057f20f883e相等。如果相等就说明密码是123456。
md5解密网站
事实上,不用手动阀一个一个去猜那么麻烦,有些网站输入密文能破解出。
而这个破解并不是真的可以从密文里看出明文,而是背后维护了一个密文明文表。已经有前人通过枚举的方式,把常见密码的md5都收集起来了,这样子的话就能快速找到对应的原始密码。这个也叫做彩虹表攻击。
彩虹表攻击是一种利用预计算哈希值来破解密码的技术。它通过建立一个包含常见密码及其对应哈希值的巨大数据库,允许攻击者快速查找某个哈希值对应的原始密码,而无需逐一尝试所有可能的密码。但彩虹表攻击只适用于简单密码。
彩虹表攻击的原理
哈希函数:通常密码存储时,系统不会直接保存明文密码,而是保存密码的哈希值。这些哈希值是通过哈希函数(如 SHA-256)计算出来的,哈希函数具有不可逆性,即很难从哈希值反推出原始密码。
预计算:彩虹表是一种预计算哈希值的表,表中包含了大量可能的明文密码及其对应的哈希值。攻击者可以在获得某个密码的哈希值后,直接在彩虹表中查找相应的明文密码,而无需计算大量哈希值。
查找匹配:一旦找到匹配的哈希值,攻击者就能够知道原始密码,从而破解密码。
这也就是为什么我们在一些应用上设置密码时,会要求我们密码增加难度,大小写加数字,这就是增加盲猜到密码的难度。
3.测试复杂密码是否能被攻破
现在我们随机拿一串复杂密码的md5,看看网站能不能解密...
加密过程:
尝试解密:
解密失败。
这也是为什么,我们在找回密码这个操作时,都是重置密码,而不是告诉你之前的密码是什么,因为它们也不知道...
这样子显然针对复杂密码很有效,但当这个密码是6位数的银行卡密码呢?
6位密码穷举只有9^6=531,441种可能,如果只用md5作为加密算法,维护一个密码表是很容易的,因此密码就很容易被破解。
二、加盐算法
所以我们要把简单密码->复杂密码,就很难破解,这里就要引入加盐算法
而我们需要加在简单密码上加上一些 “盐”使之变成复杂字符串。
为什么叫加盐是因为菜谱上的适量盐,适量到底是多少!!没人知道,只有写菜谱的人才知道
1.对密码123456演示加盐算法
这里我们采用 复杂密码 = 复杂字符串(盐值)+原始密码
123456 -> odaFEoisRjdDFjfio64854FDF!.F123456
而如果每一个密码都采用统一的盐值,就等于白给,还是可以通过穷举算出来所有的6位密码。因此,要给每一个密码都配上单独的盐值。
验证密码的比对过程:
最后比对两个红色部分是否相等来判断密码是否正确。
橙色是数据库中要储存的值。
2.盐值的储存
每个用户的盐值也需要储存在数据库里,如果单独弄一列来储存,还是不够隐秘。所以我们采用盐值与 md5(盐值+注册密码)拼接的形式。
举个例子:
蓝色部分是要存在数据库的字符串,解密时需要用到的两个字段。
拼接在一起存储:(怎么拼的?让别人猜去吧)
如图,拼接方式有很多,安全性大大提高。
只有知道是怎么拼接的,才能从这个字段中提取出来需要的 盐值 和 md(盐值+密码) 两个字符串。只有写代码的人才知道是怎么拼接的。
3.密码加盐思想总结
1.生成随机盐值:每次为新密码生成一个独特的、随机的盐值,确保不同密码的哈希值不会因为相同的输入密码而相同。
2.盐值与密码组合:将生成的盐值与用户的密码组合在一起,然后对组合后的字符串进行哈希运算。
3.存储哈希值和盐值:在数据库中巧妙存储最终的哈希值和对应的盐值,而不存储明文密码。每次验证密码时,使用相同的盐值进行哈希计算并与存储的哈希值进行比较。
4.增加破解难度:加盐有效防御了彩虹表攻击等基于预计算哈希值的攻击,因为即使攻击者拥有彩虹表,也无法直接查找原始密码的哈希值,因为盐值的随机性使得每个哈希值都是独一无二的。
三、Java代码实现
需求分析:
1.生成盐值
2.加密:用盐值对给定密码进行加密得到哈希
3.解密:给定盐值和哈希,看是否能通过校验
导包:
import org.springframework.util.DigestUtils;// 用于生成 MD5 哈希值
import org.springframework.util.StringUtils;// 用于字符串处理的工具类,检查字符串是否为空
import java.util.UUID;// 用于生成全局唯一标识符(UUID)以生成随机盐值
生成盐值和加密:
public static String encrypt(String inputPassword) {//生成随机盐值String salt= UUID.randomUUID().toString().replace("-","");//md5(明文+盐值)String finalPassword = DigestUtils.md5DigestAsHex((inputPassword+salt).getBytes());//返回最后数据库中存储的哈希(我这里采用的时盐值+md5(明文+盐值))return salt + finalPassword;}
校验方法:
public static boolean verify(String inputPassword,String sqlPassword) {//校验参数是否合法if(!StringUtils.hasLength(inputPassword)){return false;}if (sqlPassword==null || sqlPassword.length()!=64){return false;}//获取盐值String salt=sqlPassword.substring(0,32);//[0,31)//计算密文String calFinalPassword = DigestUtils.md5DigestAsHex((inputPassword+salt).getBytes());//看是否对应return (salt+calFinalPassword).equals(sqlPassword);}