Почему важен порядок аргументов в PHP-функции hash_equals()?
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 выполняется в непостоянное время, в зависимости от значений аргумента? Может ли время его выполнения зависеть от порядка аргументов (например, если 1-й аргумент равен нулю)?
Или эта заметка из документации 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);
}
Как видите, черновая реализация пыталась обрабатывать хэши различной длины, и она обрабатывала аргументы асимметрично. Возможно, этот проект реализации не первый.
Подводя итог: примечание в документации о порядке аргументов, похоже, осталось от проекта реализации.
1 ответ
Обновить:
Смотрите комментарий от Rouven Weßling, (ниже этого ответа).
...
Это скорее спекуляция, чем ответ, но, возможно, вы получите что-то из этого.
Одна из догадок, как вы упомянули, заключается в том, что для вероятной обратной совместимости функция подвергнется будущему изменению, по какой-либо причине, чтобы (1) не возвращать false на равной длине; таким образом, будучи уязвимым для информации о длине утечки - или (2) других алгоритмов / проверок, где нужно знать, что есть что - или (n) ...
Вероятный кандидат - то, что это - остаток от предложения до реализации:
Таким образом, из предложения есть:
Пользователи должны быть внимательны, так как важно, чтобы введенная пользователем строка (или хэш этой строки) использовалась в качестве второго параметра, а не первого.
Это присутствует с момента создания предложения:
Которые могут быть связаны с ссылками, например:
- Сравнение строк с постоянным временем в Symfony2 (Примечание. Фиксация с 2013 г.)
где один не возвращается на равную длину, но цикл useLen.