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


c - Why is order of arguments in PHP's hash_equals() function important?

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文档中的这个注释是对未来版本中实现更改的"保留"?


编辑

正如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);
}

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

总结:文档中关于参数顺序的注释似乎是实现草案的遗留物。

更新:

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

<小时 />

这与其说是答案,不如说是猜测,但也许你从中得到了一些东西。

<小时 />

正如你提到的,一个猜测是,如果函数在未来发生变化,出于任何原因,(1)返回等长假;因此容易受到泄漏长度信息的影响 - 或(2)其他算法/检查,需要知道哪个是哪个 - 或(n)...

<小时 />

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

  • 征求意见:定时攻击安全字符串比较功能 版本:1.0

因此,从提案一中,有:

用户

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

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

  • 征求意见:定时攻击安全字符串比较功能 版本:0.1

可以链接到参考文献,例如:

  • Symfony2 常量时间字符串比较(注意:从 2013 年开始提交。

其中不以相等的长度返回,而是循环使用Len。