为什么PHP hash_equals()函数中的参数顺序很重要?

时间:2015-01-12 22:08:38

标签: php c security php-internals timing-attack

PHP 5.6引入了hash_equals()函数,用于安全地比较密码哈希和防止计时攻击。它的签名是:

bool hash_equals(string $known_string, string $user_string)

如文档中所述,$known_string$user_string必须具有相同的长度才能有效防止定时攻击(否则,false会立即返回,泄漏已知的长度串)。

此外,文档说:

  

提供用户提供的字符串作为第二个参数非常重要,而不是第一个参数。

这个函数在参数中不对称似乎不直观。

问题是:

  • 为什么最后提供用户字符串很重要?

以下是该函数源代码的摘录:

PHP_FUNCTION(hash_equals)
{
    /* ... */

    if (Z_STRLEN_P(known_zval) != Z_STRLEN_P(user_zval)) {
        RETURN_FALSE;
    }

    /* ... */

    /* This is security sensitive code. Do not optimize this for speed. */
    for (j = 0; j < Z_STRLEN_P(known_zval); j++) {
        result |= known_str[j] ^ user_str[j];
    }

    RETURN_BOOL(0 == result);
}

至于我,关于这两个论点的实现是完全对称的。 可能产生任何影响的唯一操作是XOR运算符。

  • XOR运算符是否可能在非常量时间内执行,具体取决于参数值?可能它的执行时间取决于参数的顺序(例如,如果第一个参数为零)?

  • 或者是来自PHP的文档&#34;预留&#34;更改未来版本的实施?


修改

正如Morpfh所述,initial proposal implementation不同:

PHP_FUNCTION(hash_compare)
{
    /* ... */

    /**
     * If known_string has a length of 0 we set the length to 1,
     * this will cause us to compare all bytes of userString with the null byte which fails
     */
    mod_len = MAX(known_len, 1);

    /* This is security sensitive code. Do not optimize this for speed. */
    result = known_len - user_len;
    for (j = 0; j < user_len; j++) {
        result |= known_str[j % mod_len] ^ user_str[j];
    }

    RETURN_BOOL(0 == result);
}

如您所见,草案实现尝试处理不同长度的哈希,并且它不对称地处理参​​数。也许这个草案实施不是第一个。

总结: 关于参数的文档中的注释&#39;订单似乎是草案实施的剩余部分。

1 个答案:

答案 0 :(得分:4)

更新

  

请参阅RouvenWeßling的评论,(在此答案下面)。

...


这是一个更多的猜测,然后答案,但也许你从中获得了一些东西。


正如你所提到的,有一个猜测是,如果函数经历了未来的变化,可能会向后兼容,因为(1) not 在相等的长度上返回false;因此容易受到泄漏长度信息的影响 - 或者(2)其他算法/检查需要知道哪个是 - 或(n)......


可能的候选人是从提案到实施的剩余部分:

因此,来自 Proposal 的人有:

  

用户必须注意,因为用户提供的字符串(或该字符串的散列)用作第二个参数而不是第一个参数非常重要。

自创建提案以来,这已经存在:

可以链接到参考,例如:

其中一个返回相同的长度,但循环useLen。