这意味着啥:在长度恒定的时间内比较两个字符串 $a 和 $b?

Posted

技术标签:

【中文标题】这意味着啥:在长度恒定的时间内比较两个字符串 $a 和 $b?【英文标题】:What that mean: Compare two strings $a and $b in length-constant time?这意味着什么:在长度恒定的时间内比较两个字符串 $a 和 $b? 【发布时间】:2013-09-19 13:33:26 【问题描述】:

在学习密码哈希和保存在数据库中时,我发现了这篇文章:https://crackstation.net/hashing-security.htm#phpsourcecode

除了这个我无法理解的函数之外,一切都很清楚,为什么不使用普通相等?这意味着什么:比较两个字符串 $a 和 $b 在长度恒定的时间内。

// Compares two strings $a and $b in length-constant time.
function slow_equals($a, $b)

    $diff = strlen($a) ^ strlen($b);
    for($i = 0; $i < strlen($a) && $i < strlen($b); $i++)
    
        $diff |= ord($a[$i]) ^ ord($b[$i]);
    
    return $diff === 0;

【问题讨论】:

我假设它指的是一个“等于”函数,该函数具有恒定的执行时间以防止基于时间的攻击。 Length-constant 可能是指执行时间与字符串长度无关。当然,我可能是错的。 【参考方案1】:

当你通常比较两个字符串是否相等时,如果遇到第一个不相等,算法就会停止。

像这样:“aaa” == “aba”?第一个字符?两个“一”。第二个字符? “a”不是“b”,所以在这里停下来节省时间。不比较最后一个字符。

在比较与安全相关的字符串时,攻击者可能会因为此类比较函数的运行时间而获知哪个字符是正确的,哪个是错误的。

考虑一下使用纯文本密码的不安全做法。如果攻击者可以通过测量密码比较运行的时间来判断他猜出的密码的第一个字符是否正确,那么他只需要大约 62 次猜测(大小写字母和数字)就可以知道第一个字母。一个字母的运行时间更长,因为第一个字母与真实密码相同,然后比较了第二个字母。现在第二个字母被迭代了。再经过 62 次猜测,就知道了。

这大大削弱了安全性,因为在不知道第一个字母是否正确的情况下,您需要 62*62 次猜测两个字母的密码。有了一个线索,你只需要 62 + 62 次猜测。

一个长度常数比较函数比较所有的字母,只有在最后才显示字符串是否匹配。这样你就无法知道哪个字母已经正确了。

散列字符串会混淆一些东西,但是因为您无法知道攻击者是否预先生成了一堆散列,或者正在动态生成它们,并且如果散列不匹配,则不会暴力破解相应的密码,您不希望任何人知道哈希不匹配的位置。这是一个很小的附加安全组件,但却是一个非常重要的组件。

【讨论】:

总之,这样我们可以防止基于时间的攻击,我明白了,谢谢 如果 $diff 不是 0 via $diff = strlen($a) ^ strlen($b); 似乎可以避免循环,而不会破坏有关时间的逻辑。 这将完全绕过拥有这样一个功能的整个目的。原因是每个输入都同样慢。任何情况下都明确没有捷径。 @Sven:但即使使用原始代码,也可以猜测密码长度,因为小于密码的字符串会很快返回。 您错过了我们不比较纯文本密码,而是比较它们的哈希值的事实。无论原始密码有多不安全,这样的哈希值都具有相同的长度。我的示例使用纯文本密码场景只是为了说明为什么使用非长度常量字符串比较函数来显示信息。对哈希滥用它听起来更难,但为什么要冒险呢?

以上是关于这意味着啥:在长度恒定的时间内比较两个字符串 $a 和 $b?的主要内容,如果未能解决你的问题,请参考以下文章

在恒定时间内修剪 C++ 字符串

在恒定时间内“拆分”矩阵

密码学.NET,避免定时攻击

如何在恒定时间内仅使用算术运算计算指数?

字符串比较与散列

在 C# 中,两个问号一起意味着啥?