Библиотека password-hash в JavaScript долго
использовалась как простое средство для хеширования паролей в серверных
приложениях Node.js. Её привлекательность заключалась в минимальной
сложности интеграции и отсутствии необходимости в дополнительной
нативной компиляции. Однако архитектура подобных решений опирается на
криптографические примитивы общего назначения и не учитывает современные
требования к стойкости паролей при атаке перебором.
Ключевая проблема заключается в том, что password-hash
реализует подход «хеш + соль» без специализированной защиты от массового
перебора:
В результате такие схемы перестают соответствовать модели угроз, где атакующий обладает распределёнными вычислительными ресурсами.
Современные системы аутентификации предполагают, что утечка базы данных — это не гипотетический, а ожидаемый сценарий. При этом основная задача хеширования паролей смещается от «сохранения структуры данных» к «максимальному замедлению перебора».
В старых подходах, включая password-hash,
предполагалось:
Современная реальность включает:
Эти изменения делают быстрые хеш-функции неприемлемыми для хранения паролей.
bcrypt представляет собой адаптивную функцию хеширования паролей, основанную на Blowfish-ключевом расписании. Его ключевая особенность — параметр cost factor, который увеличивает вычислительную сложность экспоненциально.
Свойства bcrypt:
В отличие от password-hash, bcrypt позволяет
контролировать баланс между производительностью и безопасностью через
параметр сложности.
Пример использования в Node.js:
import bcrypt from "bcrypt";
const saltRounds = 12;
const hashPassword = async (password) => {
const hash = await bcrypt.hash(password, saltRounds);
return hash;
};
const verifyPassword = async (password, hash) => {
return await bcrypt.compare(password, hash);
};
Ключевой параметр — saltRounds. На практике значения
10–14 считаются типичными, но выбор зависит от серверной нагрузки.
Argon2 был победителем Password Hashing Competition и проектировался с учётом противодействия GPU и ASIC-атакам.
Его преимущества перед bcrypt:
Argon2 существует в трёх вариантах:
Пример использования:
import argon2 from "argon2";
const hashPassword = async (password) => {
return await argon2.hash(password, {
type: argon2.argon2id,
memoryCost: 2 ** 16,
timeCost: 3,
parallelism: 1
});
};
const verifyPassword = async (password, hash) => {
return await argon2.verify(hash, password);
};
Основной параметр безопасности — memoryCost, который
делает массовый перебор дорогостоящим по ресурсам памяти, а не только по
CPU.
Использование password-hash становится технически
неоправданным в следующих условиях:
Если система хранит:
то быстрые хеш-функции создают критический риск компрометации.
Любая архитектура, где база паролей может быть экспортирована (SQL injection, backup leak, misconfiguration), требует медленных KDF.
GPU-кластеры делают миллиарды проверок в секунду реальностью, что полностью ломает модели безопасности быстрых хешей.
Многие стандарты безопасности (например, OWASP рекомендации) прямо указывают на необходимость использования bcrypt, Argon2 или scrypt.
Архитектурные недостатки можно структурировать следующим образом:
Отсутствие memory hardness Алгоритм не требует значительных объёмов памяти, что делает его уязвимым к GPU.
Фиксированная или слабая адаптивность Нет полноценного механизма усложнения вычисления без смены алгоритма.
Устаревшая криптографическая модель Использование быстрых хешей не соответствует современным требованиям password-based key derivation.
Отсутствие стандартизации параметров В отличие от bcrypt/argon2, нет общепринятой схемы настройки безопасности.
Переход на современные алгоритмы требует учёта обратной совместимости.
Во время миграции система должна уметь:
Пример стратегии:
const isLegacyHash = (hash) => {
return hash.startsWith("legacy$");
};
const verifyUserPassword = async (password, hash) => {
if (isLegacyHash(hash)) {
const isValid = legacyVerify(password, hash);
if (isValid) {
const newHash = await argon2.hash(password);
await updateUserHash(newHash);
}
return isValid;
}
return await argon2.verify(hash, password);
};
password-hash
bcrypt
Argon2
Современные системы аутентификации требуют функций, которые не только
преобразуют пароль в хеш, но и создают экономический барьер для
атакующего. Быстрые алгоритмы, включая password-hash, не
обеспечивают такого барьера, тогда как bcrypt и Argon2 вводят
вычислительную и/или память-зависимую стоимость, критически усложняющую
массовый перебор.