bcrypt 是否比较“长度恒定”时间的哈希值?

信息安全 密码 php bcrypt 定时攻击
2021-09-09 14:36:08

slowEquals()我在阅读Salted Password Hashing - Doing it Right时看到了这个函数,它使用字节级异或比较来避免计时攻击。我想知道这是否也是 Bcrypt 为避免定时攻击所做的事情。我使用Openwall PHPass,它有自己的CheckPassword()方法,似乎没有异或。它如何避免定时攻击?

2个回答

散列的一个很酷的地方是,即使是对输入的一位更改也会完全改变输出。记住这一点!这与你的问题有什么关系?好吧,请容忍我一点。

在绝大多数情况下,访问盐意味着访问密码哈希。在 Bcrypt 的情况下尤其如此,因为几乎所有实现都将盐、哈希和迭代计数存储在带有分隔符的同一字符串中。也请记住这一点!

由于比较是在密码的hash上进行的,并且对输入密码的任何更改都将完全更改生成的 hash(还记得吗?),因此计时攻击的收益最多将是有关 hash 本身的信息但是,只有当攻击者可以访问盐时,这才是正确的。还记得我们说过的话吗?访问盐意味着访问哈希。这意味着这种情况下的定时攻击是无关紧要的

如果攻击者无法访问盐,那么定时攻击将给出(实际上)零信息。因此,它将给攻击者零优势。

底线:对于 Bcrypt、Scrypt 等哈希方案,定时攻击是无关紧要的。使用 和 之类的比较==不是===问题。话虽如此,作为纵深防御策略的一部分,使用恒定时间比较是一种很好的做法事实上,许多 Bcrypt 实现已经使用时间安全比较以防万一(例如,timingsafe_bcmp.cpy-bcrypt中)。

更新:

确实有一种方法可以在不了解哈希的任何组件(盐、迭代或明文值)的情况下提取有关哈希的一些信息。Oasiscircle在评论中对此进行了描述

这仍然可以使用提前退出字节比较泄漏部分哈希。示例:攻击者计算大量散列并存储它们以寻找以 0x00 开头的散列。找到具有该值的明文后,发送该明文,监听响应时间。对 255 个以上的值执行此操作,直到一个值花费的时间稍长。这是从明文创建的散列的第一个字节值。

话虽如此,我仍然持有原始答案中表达的相同观点,即使用 Bcrypt 等散列方案时定时攻击的无关性。虽然确实有这种攻击的可能,但这是极不可行的。这种攻击的计算和存储需求是巨大的,并且随着从散列中发现的每一位都呈指数级增长。

bcrypt 根本不比较散列,bcrypt 只是散列。如果您将结果与 naïve 进行比较$storedHash === $hash,那么您(理论上)很容易受到定时攻击。这已在PHPass 的 Github 票证中提出,响应为:

我之前已经研究过这个问题,我的所有研究都表明在处理正确的密码散列技术时这是不必要的。即使您链接的文章指出,“使用单向散列应该可以解决这个问题,因为当攻击者派生的输入不断变化时,很难从时序泄漏中向后工作(每次原始明文输入中的一个字节发生变化时,散列到不同的摘要) 。”

我很乐意再次调查此问题,但这些问题更多地与意外数据泄露有关,而不是在使用哈希时暴力破解密码。

所以 PHPass 并没有明确的尝试去阻止这种定时攻击,作者也不认为这个问题有问题。

PHP 中密码散列的“官方”bcrypt 实现是password_hashand password_verify,后者确实实现了恒定时间异或比较低于 5.5 的 PHP 版本有一个用户态实现