24

我刚刚在 Zend 框架的 HTTP Auth 库中遇到了这段代码。它似乎使用了一个特殊的字符串比较函数来使其更安全。但是,我不太明白评论。谁能解释为什么这个功能比做更安全$a == $b

/**
 * Securely compare two strings for equality while avoided C level memcmp()
 * optimisations capable of leaking timing information useful to an attacker
 * attempting to iteratively guess the unknown string (e.g. password) being
 * compared against.
 *
 * @param string $a
 * @param string $b
 * @return bool
 */
protected function _secureStringCompare($a, $b)
{
    if (strlen($a) !== strlen($b)) {
        return false;
    }
    $result = 0;
    for ($i = 0; $i < strlen($a); $i++) {
        $result |= ord($a[$i]) ^ ord($b[$i]);
    }
    return $result == 0;
}
4

1 回答 1

37

看起来他们正试图阻止定时攻击

在密码学中,定时攻击是一种旁道攻击,其中攻击者试图通过分析执行密码算法所花费的时间来破坏密码系统。计算机中的每个逻辑操作都需要时间来执行,并且时间可能因输入而异;通过精确测量每个操作的时间,攻击者可以回溯到输入。

基本上,如果比较正确密码和错误密码所需的时间不同,那么您可以使用时间来计算您猜对了密码的多少个字符。

考虑一个非常有缺陷的字符串比较(这基本上是正常的字符串相等函数,有一个明显的wait添加):

function compare(a, b) {
    if(len(a) !== len(b)) { 
        return false;
    }
    for(i = 0; i < len(a); ++i) {
        if(a[i] !== b[i]) {
            return false;
        }
        wait(10); // wait 10 ms
    }
    return true;
}

假设您提供了一个密码,并且(始终)一个密码需要一些时间,另一个密码大约需要 10 毫秒。这告诉你什么?这意味着第二个密码比第一个密码多一个正确的字符。

这使您可以进行电影黑客 - 您一次猜测一个字符的密码(这比猜测每个可能的密码要容易得多)。

在现实世界中,还涉及其他因素,因此您必须多次尝试密码以处理现实世界的随机性,但是您仍然可以尝试每个字符的密码,直到一个明显花费更长的时间,然后再从两个开始字符密码等。

这个函数在这里还有一个小问题:

if(strlen($a) !== strlen($b)) { 
    return false;
}

它使您可以使用定时攻击来确定密码的正确长度,这样您就不必费心猜测任何较短或较长的密码。通常,您首先要对密码进行哈希处理(这将创建等长的字符串),所以我猜他们认为这不是问题。

于 2012-05-14T02:13:12.403 回答