这两天华住数据库密码泄露,导致上亿人的开放记录和用户信息被放到黑市贩卖(机智的我从来不开房),这再次抛弃了大家对信息安全的关注。今天讨论下信息安全中的密码安全。

现在基本没有程序员在将密码明文存在数据库了,但是如果只是简单的做 MD5 加密,那跟明文也没什么区别了。

MD5 被破解的原理很简单(首先声明 MD5 的破解不是被解密的,每次提到这个问题,就能想起以前跟我较真的一个同事,想起他一脸严肃的跟我说 MD5 可以解密,我就想笑,一句话就可以反驳,如果 MD5 可以解密,那它就是全世界最牛逼的压缩工具)。MD5 的长度是固定的,无限的数据组合散列出固定长度的密文,就一定会有两个不同的明文可以得到相同的 MD5 值。

1
2
其他明文:md5(abc)    ==>     xyz
用户密码:md5(def) ==> xyz

这样攻击者将 key(密码明文)和 value(MD5 值)存入数据库,然后用密文反查明文,及时得不到 def,使用 abc 也是可以通过登录验证的,这样的暴力破解已经非常成熟。

Salt 算法

为了应对这种情况,我需要在明文上加上一点“佐料”是明文变长,这种算法我们成为加盐算法,也就是 salt 算法这样上述发生的几率就会降低,大大增加了破解的难度。

1
2
其他明文:md5(abc+salt)    ==>     yyyyy
用户密码:md5(def+salt) ==> xxxxx

因为 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 加密

03-17 01:39