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

Ale*_*rov 12 php c security php-internals timing-attack

PHP 5.6引入了hash_equals()用于安全比较密码哈希和防止定时攻击的功能.它的签名是:

bool hash_equals(string $known_string, string $user_string)
Run Code Online (Sandbox Code Playgroud)

如文档中所述,$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);
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • 或者,PHP的文档中的这个注释是对未来版本中实现更改的"保留"吗?


编辑

正如Morpfh所说,最初的提案实施是不同的:

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);
}
Run Code Online (Sandbox Code Playgroud)

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

总结: 关于参数'顺序的文档中的注释似乎是草案实现的剩余部分.

Mor*_*pfh 5

更新:

请参阅 Rouven Weßling 的评论(在此答案下方)。


这是更多的猜测而不是答案,但也许你会从中得到一些东西。


正如您所提到的,一种猜测是,如果函数在未来发生变化,无论出于何种原因,它可能会向后兼容,以 (1)返回相同长度的 false;因此容易受到泄漏长度信息的影响 - 或(2)其他算法/检查需要知道哪个是哪个 - 或(n)......


一个可能的候选者是它是从提案到实施的剩余部分:

因此,从提案一有:

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

这自提案创建以来一直存在:

可以链接到References,例如:

其中一个以相等的长度返回,而是循环 useLen。

  • RFC 和补丁作者在这里。你是完全正确的。我最初的想法是尽量避免泄漏长度。我将参数名称保留为向前兼容(参见 http://marc.info/?l=php-internals&amp;m=139318035405396&amp;w=2)还要考虑这个 [问题](http://security.stackexchange.com/questions/49849 /timing-safe-string-comparison-avoiding-length-leak) 在 security.stackexchange.com 上,作为 PHP 实现讨论的一部分被询问。 (4认同)