这两天华住数据库密码泄露,导致上亿人的开放记录和用户信息被放到黑市贩卖(机智的我从来不开房),这再次抛弃了大家对信息安全的关注。今天讨论下信息安全中的密码安全。
现在基本没有程序员在将密码明文存在数据库了,但是如果只是简单的做 MD5 加密,那跟明文也没什么区别了。
MD5 被破解的原理很简单(首先声明 MD5 的破解不是被解密的,每次提到这个问题,就能想起以前跟我较真的一个同事,想起他一脸严肃的跟我说 MD5 可以解密,我就想笑,一句话就可以反驳,如果 MD5 可以解密,那它就是全世界最牛逼的压缩工具)。MD5 的长度是固定的,无限的数据组合散列出固定长度的密文,就一定会有两个不同的明文可以得到相同的 MD5 值。
1 | 其他明文:md5(abc) ==> xyz |
这样攻击者将 key(密码明文)和 value(MD5 值)存入数据库,然后用密文反查明文,及时得不到 def
,使用 abc
也是可以通过登录验证的,这样的暴力破解已经非常成熟。
Salt 算法
为了应对这种情况,我需要在明文上加上一点“佐料”是明文变长,这种算法我们成为加盐算法,也就是 salt 算法这样上述发生的几率就会降低,大大增加了破解的难度。
1 | 其他明文:md5(abc+salt) ==> yyyyy |
因为 MD5, SHA1
已经不再安全,我们使用 SHA512
来进行加盐算法
1 | SHA512(SHA512(password), salt) |
比较安全的加盐算法应该每个密码的 salt 值都不同,最简单的做法是随机获取 salt 并存入数据库。
存入数据库,那如果被拖库了怎么办?就像这次华住事件,整个库都被人家拿走了,拿到了 salt 岂不是什么都完了。
到也未必,上述公式,只是加盐算法的简单原理,我们可以在 salt 也做散列运算,或者在 salt 上再次加盐,等等复杂的操作都可以提现在代码中,这样即使攻击者拿到 salt 想要暴力破解出用户的原密码,仍然是非常难得。
bcrypt
而另一种方式则是不将 salt 存在数据库,而是通过加密密码得到,这样每个密码的 salt 也是不同的
1 | SHA512(SHA512(password), SHA512(password)[40:60]) |
这个 salt 的获取方式,是我随意写的,具体实现需要更复杂的加密才行。
而 bcrypt 算法,就是建立在这个原理之上的,它的 salt 获取方式极其复杂,并且每次不同,导致每次对密码的加密结果都是不同的,但是 bcrypt 自己提供了验证上一次加密结果的方法,在散列加密中 bcrypt 被认为是最安全的。
而安全换了的是性能的损失,因为它的复杂性,导致了每次计算的耗时远远大于普通的加盐算法。
在一般的生产开发中加盐算法已经足够做到密码的安全保证,除非涉及绝密信息,并且可以牺牲一定性能时,才有必要考虑 bcrypt 加密