⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 yes的练级攻略 「是Yes呀」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

最近接手公司一个之前的服务,竟然发现用户密码是明文存储在数据库中!

说实话还是有点吃惊的,这至少也得搞个 MD5 存一存吧。

不过 MD5 其实也没啥用,今天我们就来盘盘密码这种敏感信息该如何存储。

数据库为什么不能明文存储密码

不仅仅是为了防止系统管理员或者 DBA 等公司人员获得用户的密码,也是防止被黑客拖库产生更大的信息泄露。

如果黑客通过不法手段获取了服务的数据库存储信息,盗取里面的内容,从而直接获得明文密码,那么影响就会很大。

因为绝大部分人所有账户的密码都会设置成一样的,只要知道一个网站的明文密码后,基本上等于搞定这个用户其他网站的所有账号,也就是撞库。

所以不能明文存储密码,需要加密下。

MD5 不是加密算法

实际上,经常有人会说拿MD5加密,这样说没问题,但是我们心里要清楚,MD5 压根就不是加密算法,它其实就是个摘要算法。

加密算法指的是把一段数据加密后,可以解密。

很明显 MD5 无法解密,只能暴力穷举破解,所以它不算是加密算法。

为什么用 MD5 存储密码不好

大部分人的密码都会设置得比较简单,比如名字缩写加个出生日期这种。

而黑客其实会针对常见的一些密码,生成彩虹表。

彩虹表:是用于加密散列函数逆运算的预先计算好的表,常用于破解加密过的密码散列。(维基百科)

就像下面的表格:

这样一来只要准备得足够充分,彩虹表足够大,那么直接对比彩虹表就能反推得出明文密码,所以直接简单用 MD5 也是不安全的。

给密码加点盐

那咋办么?

其实彩虹表大部分能找到的只是常见的密码。

基于这点,我们虽然不能强迫用户设置一些非常复杂的密码(这记忆成本太高)。

但是我们可以手动给用户的密码拼接上一些复杂的字符,然后经过哈希函数处理之后落库。

比如用户初始密码是123456,我们可以给他的密码加点盐,盐其实就是一些复杂的字符数字,比如:

这样即使不法分子盗取到密码,预先准备的彩虹表也无用(因为密码变得不常见了),使得破解的成本变高。

这种盐叫固态盐,不需要落库存储,一般在代码或者配置中保存。一旦被不法分子试出这个盐,那么继而就能通过这个盐试出别的密码。

所以推荐动态盐,即让每个账号下密码加的盐都是不一样的,这样一来,不法分子的破解成本就更高了。

动态盐需要分别为每个用户记录对应密码加的盐值,一般是落库存储,比如上图所示在用户表上加个 salt 字段。

又或者直接跟密码拼一起中间用特殊符号切分等等,比如下图用 $ 来分割。(没错,动态盐是直接存储的,也就是说攻击者可以拿到每个账号的盐)。

我还看过一些方案,比如不加字段也不用分隔符,把用户的创建时间进行处理作为动态盐,等等。

加盐这种手段仅仅只是增加了攻击者的破解成本,因为攻击者知道盐值,从而就能反推出一个值,使得这个md5(值+盐) = md5(密码+盐)

因为不论这个值是否等于密码,反正只要最终 hash 的结果是一样的,就都能登录,所以攻击者要推是可以推出来的,只不过成本会高些。

总而言之,通过摘要算法来存储密码,不法分子是可以通过暴力、彩虹表、字典等方式来破解。

如果你仅仅是用 md5 处理密码存储,那么这些破解其实成本也不是很大。乍一说你可能没啥感觉,我在网上看到一个结论:md5 来存储 6 位长度的密码(仅仅包含小写和数字),只需要 40 秒,就可以穷举所有密码。

bcrypt

因此,为了进一步给黑客们增加破解成本,需要替换 md5 这类 hash 快速的方法,换成 bcrypt 这种算法。

md5 计算只需要 1 微秒,而 bcrypt 需要 0.3 秒,速度差了 30 万倍。

1 秒 = 1000000 微秒

因此,如果本来 40 秒就能破解的话,换成 bcrypt 后变成 138 天才能破解!

bcrypt 就是这么个哈希算法,它有个迭代次数,可以使得计算变慢,非常适合这种场景!

不用摘要算法,加密存储行吗?

其实还有一种防破解的方式,就是采用加密算法。

比如采用对称加密 AES,这样只要密钥不泄露,攻击者拖库拿到密码也完全破解不了!

但是反过来想,假设密钥被泄漏了,那就是白给,比破解上述的 hash(密码+盐)更轻松,连试试都不需要。

所以加密存储的话就得看你的密钥保不保得住了。

最后

大致方案就这么几种。动态盐其实已经 OK 了,不过算法尽量别用 md5,可以用 sha1、sha256 这些,因为 md5 其实已经被破解了。

这里的破解不是说通过 md5 可以反向推出明文,而是利用 md5 hash 后的值能快速地找到另一个值使得 md5 的结果一致。

好了,今天这篇就说这么多了,更多的可以自行上网查阅。

参考资料

md5 和 bcrypt 的速度对比出处:

https://coolshell.cn/articles/2078.html

文章目录
  1. 1. 数据库为什么不能明文存储密码
  2. 2. MD5 不是加密算法
  3. 3. 为什么用 MD5 存储密码不好
  4. 4. 给密码加点盐
  5. 5. bcrypt
  6. 6. 不用摘要算法,加密存储行吗?
  7. 7. 最后