Github 的保护 webhooks 页面 说:
不建议使用普通的
运算符。像==
这样的方法执行“恒定时间”字符串比较,这使其免受针对常规相等运算符的某些定时攻击。secure_compare
比较密码时我使用
bcrypt.compare('string', 'computed hash')
。
是什么使得这是一个“安全比较”?我可以使用 Node 中的标准
crypto
库来做到这一点吗?
“恒定时间”字符串比较的要点是,无论比较目标是什么(未知值),比较都会花费完全相同的时间。这个“恒定时间”不会向攻击者透露有关未知目标值可能是什么的信息。通常的解决方案是比较所有字符,即使在发现不匹配之后也是如此,因此无论在何处发现不匹配,比较都会在相同的时间内运行。
当某些条件成立时,其他形式的比较可能会在更短的时间内返回答案,这使得攻击者能够了解他们可能丢失的内容。例如,在典型的字符串比较中,一旦发现不相等的字符,比较就会返回 false。如果第一个字符不匹配,则比较将在比匹配时更短的时间内返回。勤奋的攻击者可以利用这些信息进行更聪明的暴力攻击。
“恒定时间”比较消除了这些额外信息,因为无论两个字符串如何不相等,函数都会在相同的时间内返回其值。
在查看nodejs v4加密库时,我没有看到任何进行恒定时间比较的函数的迹象,并且根据这篇文章,有一个关于nodejs加密库缺少此功能的讨论.
crypto.timingSafeEqual(a, b)
。
jfriend 的答案一般来说是正确的,但就这个特定上下文而言(将 bcrypt 操作的输出与数据库中存储的内容进行比较),使用“==”没有风险。
请记住,bcrypt 被设计为“单向函数”,专门用于在攻击者掌握数据库时抵御密码猜测攻击。如果我们假设攻击者拥有数据库,那么攻击者不需要计时泄漏信息来知道他对密码的猜测的哪个字节是错误的:他可以通过简单地查看数据库来检查自己。如果我们假设攻击者没有数据库,那么定时泄漏信息可能会告诉我们在攻击者理想的场景中(根本不现实)他的猜测中哪个字节是错误的。即使他可以获得该信息,bcrypt 的单向属性也会阻止他利用所获得的知识。 总结:一般来说,防止定时攻击是一个好主意,但在这种特定情况下,使用“==”不会让自己陷入任何危险。
编辑:比较数据更安全、免受定时攻击的两种方法是对两组数据进行哈希并比较哈希值,或者对所有数据进行异或并将结果与 0 进行比较。如果 == 只是扫描两组数据并返回如果它发现差异,它可能会无意中播放“更暖/更冷”的声音,并引导对手直接找到他想要匹配的秘密文本。
timingSafeEqual(a, b)
,但正如评论中所述,它期望输入具有相同的长度。 这是一个问题,因为如果输入的长度不同,您不能只返回
false
,因为您将泄漏计时信息中秘密的长度。我按照@WDS的建议做了一个简单的for循环:
// (Javascript)
function equals(test, secret) {
// String comparison that does not leak timing information
let diffs = test.length !== secret.length ? 1 : 0;
for (let i = 0; i < test.length; i++) if (test[i] !== secret[i]) diffs++;
return diffs == 0;
}