Почему важен порядок аргументов в 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) ...


Вероятный кандидат - то, что это - остаток от предложения до реализации:

Таким образом, из предложения есть:

Пользователи должны быть внимательны, так как важно, чтобы введенная пользователем строка (или хэш этой строки) использовалась в качестве второго параметра, а не первого.

Это присутствует с момента создания предложения:

Которые могут быть связаны с ссылками, например:

где один не возвращается на равную длину, но цикл useLen.

Другие вопросы по тегам