Переход на bcrypt или Argon2: когда password-hash недостаточно

Библиотека password-hash в JavaScript долго использовалась как простое средство для хеширования паролей в серверных приложениях Node.js. Её привлекательность заключалась в минимальной сложности интеграции и отсутствии необходимости в дополнительной нативной компиляции. Однако архитектура подобных решений опирается на криптографические примитивы общего назначения и не учитывает современные требования к стойкости паролей при атаке перебором.

Ключевая проблема заключается в том, что password-hash реализует подход «хеш + соль» без специализированной защиты от массового перебора:

  • отсутствует memory-hard функция;
  • ограниченная или отсутствующая адаптивная стоимость вычисления;
  • использование быстрых хеш-функций криптографического уровня общего назначения;
  • слабая устойчивость к GPU/ASIC-ускорению перебора.

В результате такие схемы перестают соответствовать модели угроз, где атакующий обладает распределёнными вычислительными ресурсами.

Изменение модели угроз при хранении паролей

Современные системы аутентификации предполагают, что утечка базы данных — это не гипотетический, а ожидаемый сценарий. При этом основная задача хеширования паролей смещается от «сохранения структуры данных» к «максимальному замедлению перебора».

В старых подходах, включая password-hash, предполагалось:

  • ограниченный бюджет атакующего;
  • CPU-центрированные вычисления;
  • отсутствие специализированного оборудования.

Современная реальность включает:

  • массовое использование GPU для перебора;
  • FPGA/ASIC ускорение;
  • готовые радужные таблицы и словарные атаки с предварительным вычислением;
  • утечки больших баз, используемых для credential stuffing.

Эти изменения делают быстрые хеш-функции неприемлемыми для хранения паролей.

Почему bcrypt становится стандартом де-факто

bcrypt представляет собой адаптивную функцию хеширования паролей, основанную на Blowfish-ключевом расписании. Его ключевая особенность — параметр cost factor, который увеличивает вычислительную сложность экспоненциально.

Свойства bcrypt:

  • адаптивная стоимость вычисления;
  • встроенная соль;
  • медленное вычисление, устойчивое к GPU-ускорению (в разумных пределах);
  • проверенная временем криптостойкость.

В отличие от 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 как современный криптографический стандарт

Argon2 был победителем Password Hashing Competition и проектировался с учётом противодействия GPU и ASIC-атакам.

Его преимущества перед bcrypt:

  • memory-hard конструкция (основное отличие);
  • защита от параллелизации атак;
  • гибкая настройка памяти, времени и параллелизма;
  • более современная модель угроз.

Argon2 существует в трёх вариантах:

  • Argon2d — ориентирован на максимальную защиту от GPU, но менее устойчив к side-channel атакам;
  • Argon2i — устойчив к side-channel, но менее эффективен против GPU;
  • Argon2id — гибридный вариант, рекомендуемый по умолчанию.

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

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 перестаёт быть достаточным

Использование password-hash становится технически неоправданным в следующих условиях:

1. Наличие пользовательских аккаунтов с высокой ценностью

Если система хранит:

  • финансовые данные;
  • персональные данные;
  • корпоративные учётные записи,

то быстрые хеш-функции создают критический риск компрометации.

2. Возможность утечки базы данных

Любая архитектура, где база паролей может быть экспортирована (SQL injection, backup leak, misconfiguration), требует медленных KDF.

3. Рост вычислительной мощности атакующего

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

4. Регуляторные требования

Многие стандарты безопасности (например, OWASP рекомендации) прямо указывают на необходимость использования bcrypt, Argon2 или scrypt.

Технические ограничения password-hash

Архитектурные недостатки можно структурировать следующим образом:

Отсутствие memory hardness Алгоритм не требует значительных объёмов памяти, что делает его уязвимым к GPU.

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

Устаревшая криптографическая модель Использование быстрых хешей не соответствует современным требованиям password-based key derivation.

Отсутствие стандартизации параметров В отличие от bcrypt/argon2, нет общепринятой схемы настройки безопасности.

Практическая миграция с password-hash

Переход на современные алгоритмы требует учёта обратной совместимости.

Поддержка старых хешей

Во время миграции система должна уметь:

  • распознавать формат старого хеша;
  • проверять пароль через legacy-алгоритм;
  • при успешной проверке пересохранять пароль в новом формате.

Пример стратегии:

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);
};

Пошаговый переход

  1. введение bcrypt или Argon2 как основного метода;
  2. сохранение поддержки legacy-хешей;
  3. обновление паролей при логине пользователя;
  4. постепенное исчезновение старых хешей из базы.

Сравнительная оценка подходов

password-hash

  • быстрое вычисление;
  • минимальная защита;
  • подходит только для некритичных систем.

bcrypt

  • средний уровень защиты;
  • хорошо изучен;
  • ограниченная, но достаточная адаптивность.

Argon2

  • высокая устойчивость к современным атакам;
  • гибкая настройка ресурсов;
  • рекомендованный стандарт для новых систем.

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

Современные системы аутентификации требуют функций, которые не только преобразуют пароль в хеш, но и создают экономический барьер для атакующего. Быстрые алгоритмы, включая password-hash, не обеспечивают такого барьера, тогда как bcrypt и Argon2 вводят вычислительную и/или память-зависимую стоимость, критически усложняющую массовый перебор.