代码改变世界

md5/sha1+salt和Bcrypt

2011-12-24 04:04  lixiong  阅读(27738)  评论(10编辑  收藏

今天在weibo.com上看到一则消息说, md5/sha1+salt的方法保存密码是不安全的. 文章中用连续9Bcrypt加感叹号来强调, 保存密码一定要用Bcrypt.

这个消息非常应景, 因为csdn.net两天前把数据库弄丢了, 里面的密码是明文保存的. 我对密码和安全没有研究, 但是在我粗浅的记忆中, hash+salt是非常主流的方法. 如果说这样也不靠谱, 那我正好借这个机会复习一下.

我把密码安全分为两个等级, 黄色和红色. 当数据库丢失后, 能算出一个可以用来登陆的密码, 这个密码不一定是原文, 但是保证可以通过验证, 这个算达到黄色. 如果还能算出原文, 这个就达到了红色.

红色比黄色严重得多. 因为用户往往在多个网站上都使用了同样的密码. 如果攻击者拿到原文, 这等于说多个网站都受到影响了. 如果拿不到原文, 那攻击者最多也就破坏当前这个泄露数据库的网站, 不会影响到其它网站.

在我看来, 很多用户对安全的要求是, 如果我使用的网站A不幸阵亡了, 只要密码原文不泄漏, 就不会伤及我使用同样密码注册的其它网站. 至于在网站A上面的任何损失, 我都不在乎了.

在这个背景下, 我的本能看法是, hash+salt难道不能实现上述的要求, 一定要使用Bcrypt?

如果仔细分析一下黄色和红色的定义, 会发现一个问题. 对于一个给定的可以用来登陆的密码, 如何判定这个密码就是原文呢? 这里的解决方法通常就是对比字典, 或者观察这个密码的字面特性.

既然牵涉到字典, 情况就更加有趣了. 破解密码的两种方法分别是穷举和字典. 我从wikipedia以及介绍上Bcrypt的资料上了解到, 如果只是穷举, hash+48位的salt算起来已经比较困难了. 文章中说,半分钟可以穷举完所有的6位密码。可以想象,如果加上一个48位的salt, 按照复杂度的增加比例,要穷举完所有可能的密码,至少还是要按月算计算的吧。

在这样的情况下,如果要想得到密码原文,首先需要花大量时间把很多可能的密码都算出来,然后才能挑选原文。就算用集群计算机,这个也需要几天时间吧。我想也不是所有用户都能享受到这个待遇的吧。如果这条路走不成,那就只有反过来,根据现成的字典来算。如果不幸使用了字典中能查到的就活该倒霉了。

当然,上面的假设是窃密者不知道salt的情况. 如果salt一起丢了的话, salt对单个用户的保护就完全丢失了。这个情况下salt的作用是让窃密者必须对每个用户都单独计算。但是即便是这样,如果密码稍微复杂一点,用8位数字字母组合,暴力走一遍也需要608次方除以700M,结果是66小时。实际时间应该比这个更长一点,因为这个时间没有考虑到长度小于8位的。

为了证明我的想法,我特意花了20大洋,到http://cmd5.com/ 这个网站上买了4次破解机会。我提交了一个123456作为原文,12salt计算出来的密文。另外再提交了一个8位包含大小写数字和一个@字符的原文,12位同样salt计算出来的密文。提交的时候把salt一起提交的。明天我再看看他能计算出怎样的结果。

根据上面的分析,使用hash+salt的话,在不同情况下有不同的结果:

如果salt没有丢,除非你的确是机要人员,基本上安全。普通cracker不会花这么多精力来搞你。

如果salt丢了,情况根据密码复杂度来看。简单密码就秒破到原文了。对于8位普通程度的密码,比如315@hkBJ这样的密码,对方可以在几个小时内走到黄色等级,但需要2天时间才能开始分析原文。

再来看看使用Bcrypt的话,情况会有如何变化。Bcrypt其实是通过增加计算密文的成本来换取安全。使用Bcrypt,默认设置下登陆时间会增加5个数量级,破解成本也会增加5个数量级。所以使用Bcrypt的话,根据我的理解,情况分为两种:

如果Bcryptsalt丢了,使用简单密码或者字典中存在的密码,秒破的时间从小于一分钟变到几天时间。所以使用简单密码还是不安全的。但是如果salt没有丢,或者即便丢了但是使用了稍微复杂的密码,要达到黄色平均时间都上年了,要到红色就不可能了。

所以,总的结论是:

如果使用不安全的密码,什么都帮不上忙。

如果使用hash+salt, 事故发生的时候,如果salt丢了,算法也没有特殊的地方,只要遇上专业人员,如果密码在8位以内,要拿到可能的密码原文,基本上是一个星期的工作。我估计花1W RMB应该能找到人干。但是如果密码里面的特殊字符多一点,或者长度再长一点,基本就安全了,除非你是重要人物。

如果使用Bcrypt,那当然最好了。丢了什么都不怕。但是,使用Bcrypt的成本是,负责做认证的服务器,可能要扩容几十倍或者几百倍哦,它是靠把计算成本提高5个数量级来换取安全的。

 

作为设计人员,使用Bcrypt肯定安全很多。但是安全的代价是性能。小型的应用没有问题,但如果每秒峰值要做到上万次登陆呢?毕竟每次登录默认0.3秒的开销摆在那里,一万次是3000秒,如果要保证登陆在1秒内完成,须要3000个服务器啊。所以在大一点的应用上使用Bcrypt,登陆服务器的设计和Bcrypt参数的配置都要仔细考量。在这样的权衡下,我觉得使用hash+salt仍旧是不错的选择. 前提是要做到如下几点: salt单独存放,使用SHA512, 独立设计hash方法比如salt插到password中间,多做几层hash,另外把代码和数据库分开存放。

 

下面这篇文章详细分析了Bcrypt的性能。得到的结论是除非你给五角大楼写程序,通常的SHA512足够好了。 

 http://www.binarylogic.com/2008/11/22/storing-nuclear-launch-codes-in-your-app-enter-bcrypt-for-authlogic/ 

The level of security your app provides is really up to you. Unless you are writing apps for the pentagon, the default Sha512 is fine. Regardless, Authlogic shouldn’t get in your way or make decisions for you, so if you feel BCrypt is necessary then go for it.” 

 

作为用户来讲,主要是做到两点。首先要使用比较复杂的密码,其次是不同安全级别的网站要使用不同的密码。比如国内网站和国外网站坚决不用一样的。银行密码不用一样的。如果注册使用邮箱作为源,那这个源的密码要特别设计。

以上就是今天晚上研究了4个小时的收获。看来我7年前了解到的hash+salt,在新时代的计算能力面前的确比较脆弱了。我算重新入门了一次。多谢 @左耳朵耗子.

相关资料:

http://codahale.com/how-to-safely-store-a-password/

http://en.wikipedia.org/wiki/Bcrypt

http://en.wikipedia.org/wiki/Rainbow_table

http://en.wikipedia.org/wiki/Salt_(cryptography)

http://cmd5.com/