Метод verify: проверка пароля против хеша

Метод verify используется для проверки соответствия пароля заранее сформированному хешу. Его задача — определить, совпадает ли введённая строка с исходным паролем, который был преобразован в криптографический хеш с учётом соли и параметров алгоритма.

Основная идея заключается в том, что исходный пароль никогда не извлекается из хеша. Вместо этого выполняется повторное хеширование входного значения с теми же параметрами, после чего результаты сравниваются.

При вызове проверки происходит следующая последовательность действий:

  1. Из хеша извлекаются параметры алгоритма (тип функции, соль, итерации, длина ключа и другие настройки).
  2. Входной пароль обрабатывается тем же алгоритмом, что использовался при создании хеша.
  3. Формируется новый хеш на основе введённого пароля.
  4. Выполняется сравнение двух значений — сохранённого хеша и вычисленного.

Ключевой момент заключается в том, что сравнение должно быть устойчивым к атакам по времени выполнения (timing attacks). Поэтому библиотеки, реализующие password-hash, используют безопасные механизмы сравнения.

Формат хеша и его значение для verify

Хеш, с которым работает метод verify, обычно представляет собой строку, содержащую все необходимые параметры для проверки:

  • алгоритм хеширования (например, sha1, sha256, bcrypt-подобная схема);
  • соль;
  • количество итераций;
  • сам хешированный результат.

Пример условного формата:

algorithm:iterations:salt:hash

или более абстрактный вариант:

pbkdf2$10000$randomSalt$generatedHash

Метод verify не требует передачи параметров отдельно — они уже встроены в строку хеша.

Алгоритм проверки

Логика метода verify в библиотеке password-hash можно представить следующим образом:

  1. Разбор входного хеша.
  2. Определение используемого алгоритма.
  3. Извлечение соли.
  4. Повторное вычисление хеша для введённого пароля.
  5. Сравнение результатов.

Псевдокод:

function verify(password, storedHash) {
    const parsed = parseHash(storedHash);

    const computedHash = hashPassword(
        password,
        parsed.algorithm,
        parsed.salt,
        parsed.iterations
    );

    return safeCompare(computedHash, parsed.hash);
}

Функция safeCompare критически важна, так как обычное сравнение строк может раскрывать информацию через различие во времени выполнения.

Пример использования

В реальной среде Node.js метод verify используется крайне просто:

const passwordHash = require('password-hash');

const hash = passwordHash.generate('securePassword123');

const result1 = passwordHash.verify('securePassword123', hash);
const result2 = passwordHash.verify('wrongPassword', hash);

console.log(result1); // true
console.log(result2); // false

В данном примере:

  • первый вызов возвращает true, так как пароль совпадает;
  • второй вызов возвращает false, так как строка не соответствует исходному значению.

Особенности реализации проверки

Метод verify скрывает внутри себя несколько важных механизмов:

Автоматическое определение алгоритма

Если хеш был создан с использованием разных параметров, verify автоматически подбирает нужный алгоритм на основе метаданных внутри строки.

Использование соли

Соль не передаётся отдельно, она извлекается из хеша. Это исключает необходимость хранения дополнительных данных.

Устойчивость к атаке перебора

Каждый вызов verify выполняет полноценное хеширование, что делает массовый перебор вычислительно дорогим процессом.

Типичные ошибки при использовании verify

Сравнение строк вручную

Одна из распространённых ошибок — попытка сравнить хеши напрямую:

if (hash === passwordHash.generate(input)) {
    // некорректный подход
}

Такой подход ломает безопасность и может приводить к неправильным результатам из-за различий в соли и параметрах.

Повторное хеширование уже захешированного значения

Иногда хеш ошибочно передаётся в verify как пароль:

passwordHash.verify(hash, hash);

В этом случае сравнение теряет смысл, так как входное значение уже не является исходным паролем.

Игнорирование структуры хеша

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

Поведение при несовпадении

Если пароль не совпадает с хешем, метод verify возвращает строгое логическое значение false. Ошибки при этом не выбрасываются, поскольку несовпадение не считается исключительной ситуацией.

Однако возможны случаи, когда:

  • хеш повреждён;
  • строка не соответствует ожидаемому формату;
  • используется неизвестный алгоритм.

В таких ситуациях поведение зависит от реализации библиотеки, но чаще всего также возвращается false.

Безопасность сравнения

Ключевой аспект работы verify — защита от timing attack. При обычном сравнении строк разница во времени обработки может раскрыть информацию о совпадающих префиксах.

Безопасное сравнение реализуется так, чтобы время выполнения зависело только от длины строки, а не от её содержимого.

Пример принципа безопасного сравнения:

function safeCompare(a, b) {
    if (a.length !== b.length) return false;

    let result = 0;
    for (let i = 0; i < a.length; i++) {
        result |= a.charCodeAt(i) ^ b.charCodeAt(i);
    }
    return result === 0;
}

Роль verify в общей схеме аутентификации

В системах аутентификации verify выполняет центральную функцию проверки личности пользователя без хранения пароля в открытом виде. В связке с генерацией хеша он образует полный цикл:

  • генерация хеша при регистрации;
  • хранение результата в базе данных;
  • проверка через verify при входе.

Такой подход исключает необходимость обратного восстановления пароля и снижает риск компрометации данных даже при утечке базы.