我最近阅读了一篇关于password hashing and salting的文章,其中解释了(在“SlowEquals代码如何工作?”下)必须使用SlowEquals函数来比较输入的密码的哈希值。数据库中的密码。
据我所知,使用SlowEquals函数是因为它使用XOR而不是==因此会检查两个字符串中的每个字符,而不是在第一个不匹配的字符上失败。
有两件事我不明白:
答案 0 :(得分:11)
算法比较两个哈希值的所有字节的事实仅仅是实现的结果,并且与使用XOR无关(即,可以编写一个算法来比较所有字节,而不会在第一次不匹配时中断使用==)。使用XOR旨在避免在循环体中引入分支指令,这可能会显示由于CPU的分支预测而导致的匹配字节数的详细信息(尽管这是否是一个问题在某种程度上取决于特定的实现,以及它编写的指令。)
使用随机sleep()来屏蔽在第一次不匹配时返回的散列检查的时序并不真正起作用,因为通过采用更多样本仍然可以在给定点处区分匹配与不匹配。为了论证,如果我们假设我们在[0..100]范围内均匀分布一个随机数毫秒,并且某个位置的匹配需要2ms,并且该位置的不匹配仅需1ms(作为算法)早退出)。通过足够的采样,我们可以区分匹配和不匹配的情况,因为我们会观察到在不匹配情况下的响应范围为[1..101] ms,但在匹配情况下为[2..102] ms(假设我们可以完美地计算时间响应) 。当然,现实世界的观测会受到抖动和其他随机性的影响,但仍有可能观察到偏见。
然后当然只有实际的考虑因素 - 为什么要引入睡眠,random等,如果相对较小的修改会导致它在恒定时间运行,并消除时间攻击?
答案 1 :(得分:2)
TL; DR - 在比较密码哈希值时使用SlowEquals并不重要。
如果你试图验证一个非散列的秘密,那么使用" SlowEquals"在阻止定时攻击方面很有价值。
但是,如果您使用的计算密集型密码(PBKDF2,50k +迭代)正确,则无关紧要。为什么?因为密码哈希"假设违反"。即使攻击者窃取/知道散列和盐,也很难找到一个哈希值到那个值的明文密码,因此密码仍然受到保护。这就是加密哈希的重点,即使被盗也无法使用。当然,有人可以使用定时攻击来计算哈希,但这并不重要,因为他们仍然无法找出密码。
加上锁定功能,在X无效尝试(3-10,随你选择)后帐户被锁定,对散列密码的定时攻击从毫无价值到毫无价值。
答案 2 :(得分:2)
如果没有slowEquals 。
让我们考虑计算比较两个chararters使用2秒(真正的计算更快,但大量的测试可以工作),我们使用1234554321作为密码。 攻击者使用0000000000进行尝试。因为我们不使用slowEquals函数,因为0!= 1,比较只需2秒 所以当攻击者知道“2秒”时,他会将'0'更改为另一个,直到使用“1000000000”,然后服务器需要4秒。