md5/sha1+salt and Bcrypt

1554 查看

PHP自带的MD5和SHA1加密函数是否安全,看了很多年前的一篇博文。原文为英文,个人英语能力真的有限,翻译了一下,其中必定存在很多错误,希望各位可以指正。
原文链接


中国最大的开发者社区网站CSDN被破解了,数据库泄露。在泄露的数据库中,密码是明文存储的。人们在微博上发表关于密码和安全相关的消息。我注意到一条消息,用MD5/SHA1+salt存储密码并不安全。该条微博的作者强烈建议使用BCrypt进行加密。虽然我不擅长的加密和安全技术,但是在我的记忆中,SHA1+salt是存储密码最流行的方式。怎么可能是不安全的?

我为密码安全定义了两个级别:黄色级别和红色级别。当数据库被泄露,如果通过计算得到一个可以通过认证的密码,这时安全级别为黄色;如果通过计算可以得到原始密码,这时安全级别为红色。

红色级别的安全隐患比黄色级别严重很多。人们通常在不同的站点使用相同的密码。如果原始密码被泄露,所有的站点都存在安全隐患。如果攻击者不能计算出原始密码,那么影响的仅仅是被攻击的站点。在我的印象中,人们需要防范红色级别的安全隐患。防止黄色级别并不是硬性要求。

在我的印象中,hash+salt已经足够好了。为什么我还要使用BCrypt?

如果我们分析定义的两个级别,我们应该提出这样的问题:对于给定的通过计算得到的密码,如何判断它是否是原来的。常见的解决方案是使用数据字典或分析字面模式。当涉及到数据字典时,它将变得很有趣。攻击者通常使用暴力破解和数据字典两种方式进行密码破解。从维基百科和BCrypt的介绍来看,hash+48bit salt很难被暴力破解。这需要半分钟来遍历所有的6个字符的密码。对于48位散列,需要花费几个月时间。

在这种情况下,攻击者通常选择放弃,除非目标用户是一个重要人物。当暴力破解失败,唯一的办法就是使用数据字典。如果密码不在数据字典中,那么你将无能为力。

以上的分析基于salt不被泄露的情况。如果salt被泄漏,个人用户失去保护。在这种情况下,攻击者只需进行逐一计算。攻击者不能使用rainbowmap。如果密码复杂程度为8位字符,需要超过70小时,遍历所有的可能性。

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

  1. 如果salt仍然是安全的,那么你是安全的,除非你是一个重要人物,不然不会成为目标。正常攻击者不为为难你。
  2. 如果salt被泄露,情况取决于你密码的复杂性。对于简单的密码,破解可能只需要几秒钟。对于8位字符的密码,比如315@hkBJ,达到黄色级别的安全隐患,攻击者只需花费几个小时,但是如果要达到红色级别,需要利用集群计算机计算几天。

BCrypt牺牲性能来得到安全。它计算出hash比hash+salt要慢10000倍,因此增加了10000倍的破解成本。

对于BCrypt,如果salt被泄露,一个简单的密码破解成本也需要几天。如果使用简单密码,用BCrypt进行加密也是不安全的。但如果salt没有丢失,或者salt丢失但是密码很复杂,需要很多年才能达到黄色级别,并且不可能得到红色级别。

作为总结,用户不要使用过于简单的密码。

使用hash+salt加密的情况下,如果你的密码够复杂,不需要担心你会变成红色级别。唯一的例外是,你是攻击者的暗恋对象、伤了攻击者心的好基友,那么你将成为攻击者的目标,他不惜耗费大量时间来破解你的密码。

使用Bcrypt加密的情况下,你总是安全的,除非你使用过于简单的密码。然而,由于Bcrypt性能的原因,如果你需要使用Bcrypt,那么你需要购买更多的web服务器用来密码验证。如果你有2个验证服务器,现在,你需要购买20000个服务器!

当然你可以配置BCrypt,使其更快,但是安全性将会下降。或者,你可以缓存明文密码,并在内存中计算出的哈希值,但如果内存转储泄漏,所有的明文密码将被泄露。

综上所述,如果你采用以下建议,建议使用hash+salt进行加密:

  1. 单独存放hash和salt。

  2. 强制用户使用强密码。

  3. 设计自己的哈希函数。不要简单地复制粘贴常见开源代码。