过去一段时间来, 众多的网站遭遇用户密码数据库泄露事件。这也给大家提醒,到底应该如何存储“密码”呢?
一句话的结论就是,存储bcrypt, scrypt等算法输出的内容,不要用salted hash的方式存储密码,不要用加密的方式存储密码,当然,更不要明文存储。
菜鸟方案-使用明文或者加密存储
加密存储的方式其实和明文存储没有区别。密码加密后一定能被解密获得原始密码,同时管理员也存在获取原始密码,利用同样的帐号登陆其他互联网服务的可能。
入门方案-将明文密码做单向哈希后存储
单向Hash算法(MD5, SHA1, SHA256等)可以保证管理员几乎不能恢复原始密码。但它有两个特点:
1)从同一个密码进行单向哈希,得到的总是唯一确定的摘要
2)计算速度快。随着技术进步,尤其是显卡在高性能计算中的普及,一秒钟能够完成数十
亿次单向哈希计算
结合上面两个特点,考虑到多数人所使用的密码为常见的组合,攻击者可以将所有密码的常见组合进行单向哈希,得到一个摘要组合, 然后与数据库中的摘要进行比对即可获得对应的密码。这个摘要组合也被称为rainbow table。
更糟糕的是,一个攻击者只要建立上述的rainbow table,可以匹配所有的密码数据库。
进阶方案-加盐的哈希
将明文密码混入“随机因素“就是所谓的盐,然后进行单向哈希后存储,也就是所谓的”Salted Hash”。
这个方式相比上面的方案,最大的好处是针对每一个数据库中的密码,都需要建立一个完整的rainbow table进行匹配。 因为两个同样使用“passwordhunter”作为密码的账户,在数据库中存储的密码摘要完全不同。
10多年以前,因为计算和内存大小的限制,这个方案还是足够安全的,因为攻击者没有足够的资源建立这么多的rainbow table。 但是,在今日,因为显卡的恐怖的并行计算能力,无需建立完整的rainbow table, 这种攻击已经完全可行。
专家方案-可调整强度的特定密码哈希算法
这类算法有一个特点,算法中有个因子,用于指明计算密码摘要所需要的资源和时间,也就是所谓的计算强度。计算强度越大,攻击者建立rainbow table越困难,以至于不可继续。典型的算法包括PBKDF2, bcrypt, scrypt等。
也就是说,故意延长一个密码匹配的计算时间,如果一个密码匹配需要1秒钟,那么匹配1000万个密码组合就需要115天,这个开销就非常大。
这类算法也可以保证即使计算能力不断提高,只要调整算法中的强度因子,密码仍然不可能被轻易的攻破,同时不影响已有用户的登陆。关于这些算法之间的具体优劣比较,请参考原文。