SHA-1是否适合用于密码存储?

155

结论:SHA-1对抗预像攻击是安全的,但易于计算,这意味着更容易进行暴力破解或字典攻击(SHA-256等后继哈希函数也是如此)。根据情况,设计为计算复杂的哈希函数(如bcrypt)可能是更好的选择。


有些人经常说"SHA-1已经被破解了",所以我想了解这到底是什么意思。假设我有一个SHA-1密码哈希的数据库,并且攻击者使用最先进的SHA-1破解算法和拥有10万台机器的僵尸网络获得了访问权限。(控制10万台家用计算机意味着他们可以每秒执行大约10^15次操作)。

  1. 找到任何一个用户的密码需要多长时间?
  2. 找到给定用户的密码需要多长时间?
  3. 找到所有用户的密码需要多长时间?
  4. 找到一种作为其中一个用户登录的方法需要多长时间?
  5. 找到一种作为特定用户登录的方法需要多长时间?

如果密码被加盐,情况会怎样变化?加盐的方法(前缀、后缀、两者都有,或者更复杂的异或等)是否重要?

在经过一番搜索后,这是我的当前理解。如果我误解了什么,请在答案中纠正。

  • 如果没有盐值,彩虹表攻击可以立即找到所有密码(除了极长的密码)。
  • 如果存在足够长的随机盐值,最有效的找出密码的方法是暴力破解或字典攻击。既不是碰撞攻击也不是原像攻击有助于找出实际密码,因此对 SHA-1 的密码学攻击在这里没有帮助。使用什么算法甚至并不重要 - 甚至可以使用 MD5 或 MD4,密码也同样安全(因为计算 SHA-1 哈希会慢一些,所以还是有一点区别的)。
  • 为了评估“同样安全”的安全性,假设单次 sha1 运行需要 1000 次操作,并且密码包含大写字母、小写字母和数字(即,60 个字符)。这意味着攻击者每天可以测试 10156060*24 / 1000 = 约 1017 个可能的密码。对于暴力破解攻击来说,这意味着在 3 小时内测试所有不超过 9 个字符的密码,在一个星期内测试不超过 10 个字符的密码,在一年内测试不超过 11 个字符的密码。(每增加一个字符,所需时间就要增加 60 倍。)字典攻击要快得多(即使是一个单独的计算机攻击者也可以在几个小时内进行),但只能找到弱密码。
  • 为了登录用户,攻击者不需要找出确切的密码;找到一个产生相同哈希值的字符串就足够了。这被称为第一原像攻击。据我所知,没有对 SHA-1 的原像攻击。(暴力破解需要 2160 操作,这意味着我们理论上的攻击者需要 1030 年才能完成。理论可能性的极限约为 260 操作,攻击需要几年的时间。)有针对缩小版本 SHA-1 的原像攻击,但影响微乎其微(对于使用 44 步而不是 80 步的缩小版 SHA-1,攻击时间从 2160 操作降至 2157)。有针对 SHA-1 的碰撞攻击是在理论可行范围之内的(最好的攻击将时间从 280 减少到 252),但即使没有盐值,这些攻击也对密码哈希毫无用处。
简而言之,使用SHA-1存储密码似乎非常安全。我有什么遗漏吗?
更新:Marcelo指出了一篇文章,提到在2的106次操作中进行第二前像攻击。(编辑:正如Thomas解释的那样,这种攻击是一种假设构造,不适用于现实场景。)尽管如此,我仍然看不出这对于将SHA-1用作密钥派生函数构成危险。是否有普遍的好理由认为碰撞攻击或第二前像攻击最终可以被转化成第一前像攻击?

2
这篇文章已经有7年的历史了,自上次编辑以来发生了很多事情。SHA-1已不再被认为足够安全用于密码哈希处理。 - GordonM
@GordonM 发生了什么?随着计算能力的增长,SHA-1碰撞攻击变得越来越实用,但它们在这里并不是真正相关的。SHA-1从来没有真正为密码哈希提供安全性(快速哈希通常不是),但在某种程度上,它仍然是AFAIK。 - Tgr
7个回答

216
你的问题的简短回答是:SHA-1是目前可获得的最安全的。MD5也可以,甚至MD4也可以;但这可能会让一些投资者感到紧张。为了公共关系,最好使用“更好”的哈希函数,例如SHA-256,即使将其输出截断为160或128位(以节省存储成本)。一些SHA-3 round-2 candidates似乎比SHA-1更快,同时被认为“更安全”;然而它们仍然有点新,因此现在坚持使用SHA-256或SHA-512是更安全的路线。这会让你看起来专业和谨慎,这是好的。
请注意,“尽可能安全”并不等于“完全安全”。请参见下面的相当冗长的解释。
关于已知攻击:
对MD4、MD5和SHA-1的已知攻击是关于碰撞的,这不影响预像阻力。已经显示MD4有一些弱点,可以(只理论上)在试图破解HMAC/MD4时利用,但这不适用于你的问题。Kesley和Schneier在论文中提出的2^106秒预像攻击是一个通用的折衷方案,仅适用于非常长的输入(2^60字节;那是一百万个TB - 注意106+60超过了160;这就是你看到折衷方案没有任何魔术的地方)。

接下来的内容假设您使用的哈希函数(例如SHA-1)是一个“黑盒子”,没有攻击者可能使用的特殊属性。即使使用“破损”的哈希函数MD5和SHA-1,您现在也有这个。

关于彩虹表:

“彩虹攻击”实际上是字典或暴力攻击的成本分摊。它是Hellman于1980年首次描述的时间-内存权衡的派生物。假设您有N个可能的密码(这是您的字典大小,如果您考虑用输出为n位的哈希函数进行暴力破解,则为2n),那么有一种时间共享攻击,其中您预先计算N个散列密码并将其存储在一个大表中。如果您对哈希输出进行排序,则可以在单个查找中获取密码。彩虹表是一种智能存储该表的方法,具有大大减少的空间。您只存储N/t个散列密码,并使用O(t2)次查找来破解密码。彩虹表使您能够处理比您实际可以存储的预计算表大得多的虚拟表。

然而,无论是彩虹还是非彩虹,攻击者仍然必须至少运行完整次攻击。这可以看作是几个连续的优化层:

  1. 暴力破解/字典攻击对于破解每个密码的成本为N
  2. 使用预先计算的表,攻击者只需支付该成本N一次,然后可以攻击许多密码,每个密码的额外成本非常小。
  3. 如果预先计算的表是彩虹表,则N可能会更大,因为存储成本降低了。瓶颈在于攻击者可以集中的CPU功率,而不是他的硬盘大小。

如果N足够大,使得哈希N个密码的CPU成本荒谬,那么这种攻击是不可行的,无论是否使用彩虹表。这意味着具有80位或更多输出的(预像抗性)哈希函数足以使暴力攻击变得不可行。

关于盐:

盐是打败预先计算的一种方法。在上面的描述中,盐将攻击者带回到步骤1:盐防止攻击者在多个攻击密码之间共享O(N)成本。预先计算的表,a fortiori彩虹表,不再可行。

您需要进行盐值处理,因为当哈希数据包含在密码中时,即适合于随机人类的大脑的内容,那么N可能相当低:人类很难选择和记住密码。这就是所谓的“字典攻击”:使用潜在密码空间(“字典”)的缩小空间,假定许多用户密码将在该特别选定的空间中。

因此,盐值至少可以防止攻击者使用预计算表,特别是预计算彩虹表。这假设攻击者能够破解一个或两个密码;我们不希望他用很少的额外开销就能破解1000个其他密码。

此外,盐值对公共关系有好处。

关于SHA-1成本:

SHA-1的基本成本大约为哈希64字节块。这就是SHA-1的工作原理:数据被填充,然后分成64字节块。在Intel Core2系统上处理单个块的成本约为500个时钟周期,这是针对单个核心的。MD5和MD4速度更快,分别计数约为400和250个周期。不要忘记,大多数现代CPU都有多个核心,因此请相应地乘以倍数。

一些加盐方案规定使用巨大的盐;例如,输入哈希函数的实际上是一个128位盐的40000个连续副本,后跟密码本身。这使得密码哈希更加昂贵(例如,在我的示例中增加了10000倍的成本),对于合法用户和攻击者都是如此。这是否是一个好主意取决于设置。对于桌面系统的登录来说,这很好:用户甚至不会注意到花费了10ms来哈希他的密码,而不是1微秒;但攻击者的成本已经提高了非常明显的10000倍。在每秒有数千个客户端的共享服务器上,总成本可能变得禁止。从概念上讲,通过相同的因素为合法用户和攻击者提高门槛并不是最终的良好安全措施;但在某些特定情况下,这可能是值得考虑的想法。
关于在线攻击:
以上所有内容都是关于打败离线攻击。离线攻击是一种攻击,攻击者拥有测试密码所需的所有数据;例如,攻击者可以获得保存哈希密码的数据库的副本。在离线攻击中,攻击者仅受计算资源的限制。相反,在线攻击是一种攻击,攻击者必须通过诚实的验证器进行每次猜测(例如,攻击者只是尝试在被攻击的系统上登录)。通过强制限制每秒可以尝试多少个密码来防止在线攻击。极端的例子是智能卡,在三次错误的PIN后关闭。
通常,为了密码安全,更值得的是将系统设置为不允许攻击者进行离线攻击。这就是Unix系统所做的:散列密码以前存储在可读的世界级文件/etc/password中,现在存储在/etc/shadow文件中,该文件受到读取访问的保护,只有少数特权应用程序可以访问。这里的假设是,如果攻击者可以读取/etc/shadow,那么他可能已经对系统拥有足够的控制权,他实际上不再需要密码...

6
回答很好。我唯一不同意的是“从概念上讲,将合法用户和攻击者的门槛提高相同比例并不是最终的良好安全措施” - 攻击者必须进行比用户多几倍的操作。为用户登录增加一个时钟周期,对攻击者来说需要增加数百万个时钟周期。 - Nick Johnson
1
@Thomas 这个说法是准确的,而且在可预见的未来也很可能保持准确。由于常见密码的质量较差,黑客可以通过任何类型的哈希猜测实际密码。猜测“123456”,你总会得到一些命中率。无论使用什么密码存储方式,这都将保持不变。 - tylerl
1
这只是我的观点,但既然更强的密码加密已经广泛可用,为什么要坚持使用SHA1呢?一年前,MD5被认为是“安全”的,现在它已经不再安全了 - 同样的事情可能随时发生在SHA1身上。就我个人而言,我会从现在开始押注于Blowfish - 它似乎有更好的声誉和更少的加密社区专家关注,而且几乎可以在任何地方使用,所以没有理由冒险使用SHA1。 - mindplay.dk
1
@Aerovistae:你可能想看一下安全.SE网站上那个答案,它包含了更多的密码哈希分析和最新细节。 - Thomas Pornin
1
@GordonM:SHA-1碰撞对密码哈希的安全性没有任何影响。 - Thomas Pornin
显示剩余17条评论

30

之前的回答都没有提到GPU,现在GPU可以将SHA-1哈希并行化处理,使整个数据库可以在几分钟或几小时内强制破解,而不是需要几天甚至几周时间,即使密码已被加盐。

现代密码哈希算法,例如bcrypt或scrypt,专门设计为难以在GPU上运行,因为它们是块密码,并具有更高的内存需求(GPU中的内存访问不能以同样的方式并行化处理)。 它们还具有“工作函数”,允许它们在技术改进时变得更慢。

简而言之,您应该只使用最适合工作的工具。 而SHA-1远远落后于现代技术。

欲了解更多信息,请参考以下文章:


2
“现代密码哈希算法,如bcrypt或scrypt,专门设计成难以在GPU上运行。” - 你是不是指“bcrypt或scrypt”?PBKDF2只是迭代哈希,其中没有任何会对GPU造成问题的东西。 - Tgr
4
请告诉我你使用的GPU型号,我会购买同样的。如果你可以在“分钟”内执行2^160个SHA-1计算(这将不到“小时”,所以最多为59分钟),那么你需要能够每秒执行超过10^44次计算。由于PCIe传输速度大约为128GT/s,你的GPU必须拥有出色的内存。我想要它。 - Damon
3
@Damon: 你好像假设用户的密码要么很简单(<8位熵值),要么无法破解(>60位熵值)。你完全忽略了介于这两者之间、熵值在10到60之间的用户。这些用户使用bcrypt、彩虹表和GPU,他们通常占典型用户群体的约80%。 - jammycakes
1
抱歉...我应该说,“这些用户是bcrypt、彩虹表和GPU产生最大差异的用户”。 - jammycakes
3
有关一些统计数据和分析,请参见http://www.troyhunt.com/2011/06/brief-sony-password-analysis.html-尽管36%的用户选择出现在密码字典中的密码,但只有2-3%的用户选择最常见的密码。 - jammycakes
显示剩余4条评论

8
SHA1是一种“消息摘要”,它从未被设计为密码哈希(或密钥派生)函数。(虽然它可以用作KDF的构建块,例如使用HMAC-SHA1的PBKDF2。)
密码哈希函数应该防御字典攻击和彩虹表攻击。一个好的密码哈希方案也应该防止攻击者通过使用GPU、FPGA或ASIC获得优势。已经设计了几种算法来实现这些目标。
目前,最好的选择可能是Argon2。这个家族的密码哈希函数在2015年赢得了密码哈希竞赛。
如果Argon2不可用,其他选择包括scrypt和较旧的bcrypt。最后,如果没有这些选项,PBKDF2仍然比使用消息摘要作为密码哈希函数要好得多,它是一个老式的NIST标准。
维基百科有这些函数的页面:

7

您的描述对当前技术状态来说是准确的。

然而,您不应该只使用单个哈希函数迭代:至少应该迭代多次(1000次哈希迭代可以将攻击者的工作量增加1000倍。它同样会增加您的工作量,但您进行的密码哈希比他们少得多)。

理想情况下,您应该使用现有的密码存储原语,例如这里所描述的。


迭代数千次并不是你想象中的好主意。这会增加哈希冲突的风险。http://yorickpeterse.com/articles/use-bcrypt-fool - jammycakes
1
那篇文章看起来非常混乱。安全哈希函数不会通过迭代哈希失去明显的熵,而迭代哈希是诸如PBKDF2和scrypt等关键拉伸方案的核心组成部分。即使是作者推荐的bcrypt也使用了类似的结构。他的“攻击”依赖于找到哈希的预像 - 在这种情况下,大多数使用该哈希的构造都已经彻底破坏了。最后,我不建议人们直接使用迭代哈希 - 正如我在我的问题中所说,你应该使用专为此目的设计的现有原语。 - Nick Johnson

4
在SHA-1中发现了严重漏洞,使得搜索速度比暴力破解快得多。虽然它仍然很难攻克,但这种情况不会持续太久;谨慎的程序员更喜欢使用SHA-2系列中的某个东西。
从关于原始2005年结果的这篇文章中可以看到:
“是时候走,但不是跑,到消防出口。你看不到烟雾,但火警已经响了。”
并不是说当前的密码分析使SHA-1不安全,而是加密社区担心更糟糕的消息可能就在不远处。这种担忧也适用于SHA-2,它表现出与SHA-1相同的缺陷,尽管搜索空间要大得多,因此一直在寻找SHA-3
简而言之,SHA-1现在是安全的,而且可能在未来的一段时间内都是如此,但加密社区对其前景感到不舒服。

你能提供一个链接吗?正如我所说,我能找到的最好的预像攻击可以让搜索速度快8倍,即使这样也需要省略SHA-1一半的步骤才能生效。(另外,我认为这是第二次预像攻击,对于密码哈希毫无用处。) - Tgr
考虑到最近的新闻,我对来自NSA的东西也持怀疑态度 :) - Alex W

3
如果您存储了加盐的密码,SHA-1对于实际目的来说是可以的。虽然SHA-2被认为更安全,但除非您有真正偏执的理由,否则SHA-1不是问题。
以下是NIST的说法
“到目前为止,关于SHA-1的结果并没有对其安全性提出质疑。然而,由于技术的进步,NIST计划在2010年之前逐渐淘汰SHA-1,采用更大、更强的哈希函数(SHA-224、SHA-256、SHA-384和SHA-512)。”

这是NIST 2004年的评论。他们2010年的草案建议表示,SHA-1在2010年之后被批准用于所有非数字签名生成应用程序。 - Tgr

3

截至2017年2月,不应再认为SHA-1是安全的。谷歌已经成功地对完整的非减轮SHA-1进行了冲突攻击 ( 报告链接)。请点击此处查看谷歌的公告。

编辑:正如其他人指出的那样,密码不会受到哈希冲突攻击的影响。然而,作为一般准则,我不会选择SHA-1用于安全相关的应用程序。有更好的替代方案。


1
好的,找到一个SHA-1碰撞大约需要6500个CPU年和100个GPU年,这不是一种生产攻击。破解密码并不是针对所有可能的输入进行暴力破解,而是针对1000万个常用密码列表进行破解。这是论文链接 - zaph
2
漏洞在于仅使用任何哈希函数来保护密码。仅使用哈希函数是不够的,仅添加盐也很难提高安全性,因为加密哈希非常快。相反,应该使用一个随机盐迭代 HMAC 约 100ms,并将盐与哈希一起保存。使用 PBKDF2(又名 Rfc2898DeriveBytes)、password_hash/password_verifyBcrypt 和类似的函数。关键是让攻击者花费大量时间通过暴力破解找到密码。保护用户非常重要,请使用安全的密码方法。 - zaph
碰撞不是预像,密码也不是签名。碰撞攻击对密码无效,因为它们需要原始明文的知识。 - Tgr
Tgr:同意,谢谢。Zaph:是的,为了防止彩虹攻击,使用盐和慢速加密哈希是推荐的做法之一,我在这个答案中没有特别提到。 - RavenMan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接