为什么 PHP 的 hash_equals() 函数中的参数顺序很重要?
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
,泄漏长度已知字符串)。
此外,文档说:
It is important to provide the user-supplied string as the second parameter, rather than the first.
函数的参数不对称对我来说似乎不直观。
问题是:
- 为什么最后提供用户字符串很重要?
以下是函数源代码的摘录:
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 的文档中的这条注释是 "reservation" 用于在未来版本中实现的更改?
编辑
因为 Morpfh stated, the 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);
}
如您所见,实施草案试图处理不同长度的哈希值,并且它以非对称方式处理参数。也许这个实施草案不是第一个。
总结: 文档中关于参数顺序的说明似乎是实施草案的遗留问题。
更新:
See comment from Rouven Weßling, (below this answer).
…
这是更多的猜测,而不是答案,但也许你能从中得到一些东西。
正如您提到的,一个猜测是,如果函数在未来出于任何原因进行更改,可能是为了向后兼容 (1) not return false 等长;因此容易受到泄漏长度信息的影响 - 或 (2) other algorithms/checks 其中需要知道哪个是哪个 - 或 (n) ...
一个可能的候选者是它是实施提案的遗留物:
因此,从提案中有一个:
Users have to be mindful, as it is important that the user supplied string (or a hash of that string) is used as the the second parameter not the first.
自提案创建以来一直存在:
可以链接到参考文献,例如:
- Symfony2 constant-time string comparison(注:从 2013 年开始提交。)
其中一个 not return 等长,但循环 useLen。
PHP 5.6 引入了 hash_equals()
功能,用于密码哈希的安全比较和防止定时攻击。它的签名是:
bool hash_equals(string $known_string, string $user_string)
如文档所述,函数$known_string
和$user_string
的长度必须相同才能有效防止定时攻击(否则会立即返回false
,泄漏长度已知字符串)。
此外,文档说:
It is important to provide the user-supplied string as the second parameter, rather than the first.
函数的参数不对称对我来说似乎不直观。
问题是:
- 为什么最后提供用户字符串很重要?
以下是函数源代码的摘录:
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 的文档中的这条注释是 "reservation" 用于在未来版本中实现的更改?
编辑
因为 Morpfh stated, the 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);
}
如您所见,实施草案试图处理不同长度的哈希值,并且它以非对称方式处理参数。也许这个实施草案不是第一个。
总结: 文档中关于参数顺序的说明似乎是实施草案的遗留问题。
更新:
See comment from Rouven Weßling, (below this answer).
…
这是更多的猜测,而不是答案,但也许你能从中得到一些东西。
正如您提到的,一个猜测是,如果函数在未来出于任何原因进行更改,可能是为了向后兼容 (1) not return false 等长;因此容易受到泄漏长度信息的影响 - 或 (2) other algorithms/checks 其中需要知道哪个是哪个 - 或 (n) ...
一个可能的候选者是它是实施提案的遗留物:
因此,从提案中有一个:
Users have to be mindful, as it is important that the user supplied string (or a hash of that string) is used as the the second parameter not the first.
自提案创建以来一直存在:
可以链接到参考文献,例如:
- Symfony2 constant-time string comparison(注:从 2013 年开始提交。)
其中一个 not return 等长,但循环 useLen。