安全字符串比较功能

lau*_*ent 24 php security string zend-framework compare

我刚刚在Zend Framework的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;
}
Run Code Online (Sandbox Code Playgroud)

Rei*_*ica 36

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

在密码学中,定时攻击是一种侧信道攻击,攻击者通过分析执行加密算法所花费的时间来试图破坏密码系统.计算机中的每个逻辑操作都需要时间来执行,并且时间可以根据输入而不同; 通过精确测量每个操作的时间,攻击者可以向后返回输入.

基本上,如果比较正确的密码和不正确的密码需要不同的时间,那么您可以使用时间来确定您猜对的密码的字符数.

考虑一个非常有缺陷的字符串比较(这基本上是正常的字符串相等函数,有明显的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;
}
Run Code Online (Sandbox Code Playgroud)

假设你给了一个密码,它(一直)需要一些时间用于一个密码,而大约10毫秒的时间用于另一个密码.这告诉你什么?这意味着第二个密码比第一个密码多一个字符.

这可以让你进行电影黑客攻击 - 你可以一次猜出一个密码(这比猜测每一个可能的密码容易得多).

在现实世界中,还有其他因素,所以你必须多次尝试使用密码来处理现实世界的随机性,但你仍然可以尝试每一个字符密码,直到一个明显需要更长时间,然后开始两个字符密码等.

这个功能在这里仍有一个小问题:

if(strlen($a) !== strlen($b)) { 
    return false;
}
Run Code Online (Sandbox Code Playgroud)

它允许您使用计时攻击来确定密码的正确长度,这使您无需猜测任何更短或更长的密码.一般来说,你想首先哈希你的密码(这将创建相等长度的字符串),所以我猜他们不认为这是一个问题.

  • @iWantSimpleLife:密码应该**始终**预先存储在数据库中. (5认同)
  • @iWantSimpleLife - 考虑一种情况,即您没有哈希密码,正确的密码长度为5个字符.如果您提交的密码长度为1个字符,则会立即返回.长度为2个字符时,它会立即返回,最多可以返回5个字符,此时它会突然显示稍长的时间,然后在6时它会立即返回.即使`strlen`没有在恒定时间内返回(比如对于更长的字符串需要更长的时间),那么你仍然可以进行回归并找出比较需要更长时间的长度. (2认同)