Вынесение хеширования в отдельный микросервис

Вынесение хеширования паролей на базе bcrypt.js в отдельный микросервис решает задачу изоляции криптографически чувствительных операций от основной бизнес-логики приложения. Такой подход становится особенно актуальным в распределённых системах, где аутентификация используется множеством сервисов и требуется единая политика безопасности.

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

Выделение микросервиса позволяет централизовать управление параметрами хеширования, унифицировать поведение системы и упростить аудит безопасности.


Роль bcrypt.js в изолированном сервисе

Библиотека bcrypt.js реализует алгоритм bcrypt полностью на JavaScript без нативных зависимостей. Это упрощает развертывание микросервиса в контейнерных средах, где сборка native-модулей может быть проблематичной.

Основные операции:

  • hash(password, saltRounds) — создание хеша
  • compare(password, hash) — проверка соответствия пароля хешу
  • genSalt(saltRounds) — генерация соли (обычно используется внутри hash)

В контексте микросервиса чаще всего используется только две операции: создание хеша и проверка пароля.


Структура микросервиса хеширования

Типовой сервис строится как stateless HTTP API, что позволяет масштабировать его горизонтально без изменения логики.

Основные компоненты:

  • HTTP API (REST или gRPC)
  • bcrypt.js как ядро вычислений
  • очередь запросов (опционально при высокой нагрузке)
  • rate limiting
  • логирование операций без раскрытия чувствительных данных

Пример логической структуры:

auth-hash-service/
 ├── src/
 │   ├── controllers/
 │   ├── services/
 │   ├── routes/
 │   ├── utils/
 ├── app.js
 ├── config.js
 ├── package.json

API-интерфейс микросервиса

Проектирование API должно исключать утечку чувствительной информации. Пароли никогда не сохраняются и не логируются.

Хеширование пароля

POST /hash

Запрос:

{
  "password": "user_password",
  "cost": 12
}

Ответ:

{
  "hash": "$2a$12$EIX/b..."
}

Проверка пароля

POST /compare

Запрос:

{
  "password": "user_password",
  "hash": "$2a$12$EIX/b..."
}

Ответ:

{
  "match": true
}

Реализация сервиса на Node.js

Ядро сервиса базируется на Express или Fastify.

Пример логики хеширования:

import bcrypt from 'bcryptjs';

export async function hashPassword(password, cost = 12) {
  const salt = await bcrypt.genSalt(cost);
  return bcrypt.hash(password, salt);
}

Проверка:

import bcrypt from 'bcryptjs';

export async function comparePassword(password, hash) {
  return bcrypt.compare(password, hash);
}

Контроллер:

export async function hashController(req, res) {
  const { password, cost } = req.body;

  const hash = await hashPassword(password, cost);

  res.json({ hash });
}

Причины вынесения в отдельный сервис

Изоляция безопасности

Пароли обрабатываются в отдельном контуре, который можно:

  • ограничить в сетевом доступе
  • изолировать в приватном VPC
  • контролировать через отдельные IAM политики

Это снижает поверхность атаки всей системы.


Централизация политики хеширования

Вместо рассинхронизации параметров bcrypt в разных сервисах, микросервис задаёт единый стандарт:

  • cost factor (например, 10–14)
  • формат соли
  • версия алгоритма

Изменения происходят централизованно без перекомпиляции всех сервисов.


Упрощение масштабирования

bcrypt является CPU-bound операцией. Вынесение позволяет:

  • масштабировать сервис отдельно от API
  • выделять CPU-интенсивные инстансы
  • использовать autoscaling по нагрузке

Производительность и cost factor

Параметр cost напрямую влияет на время вычисления:

t = 2^{cost}

где t — относительное время выполнения.

Рост cost на 1 увеличивает время хеширования примерно в 2 раза. Это означает, что выбор значения cost становится критическим для балансировки безопасности и производительности.

Типичные значения:

  • 10 — высокая скорость, средняя безопасность
  • 12 — баланс
  • 14+ — высокая безопасность, значительная нагрузка

Очереди и асинхронная обработка

При высокой нагрузке синхронные HTTP-запросы к bcrypt могут стать узким местом. В таких случаях вводится очередь задач.

Схема:

  1. API получает запрос
  2. отправляет задачу в очередь (Redis / RabbitMQ)
  3. worker выполняет bcrypt.hash
  4. результат возвращается через polling или callback

Преимущества:

  • контроль нагрузки CPU
  • предотвращение деградации API
  • предсказуемость времени ответа системы

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

Микросервис хеширования должен быть недоступен извне публичной сети. Основные меры:

  • mTLS между сервисами
  • API key или JWT для внутренних вызовов
  • IP allowlist
  • ограничение payload size

Особое внимание уделяется защите от:

  • повторных атак (replay attacks)
  • массовых запросов на hash (DoS на CPU)
  • утечки хешей через логи

Логирование и наблюдаемость

Логи должны исключать любые чувствительные данные.

Разрешено:

  • время запроса
  • cost factor
  • статус операции
  • latency

Запрещено:

  • пароль
  • hash (в большинстве случаев)
  • входные payload полностью

Метрики:

  • average hashing time
  • CPU utilization
  • queue length
  • error rate

Проблемы и ограничения архитектуры

Латентность сети

Вынесение bcrypt в отдельный сервис добавляет сетевую задержку. В некоторых сценариях локальное выполнение быстрее, чем RPC-вызов.

Дополнительная сложность инфраструктуры

Появляются:

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

Потенциальная точка отказа

При неправильной архитектуре микросервис хеширования может стать критическим узлом системы аутентификации.


Стратегии отказоустойчивости

Для минимизации рисков применяются:

  • горизонтальное масштабирование инстансов
  • fallback на локальное хеширование (в редких архитектурах)
  • circuit breaker на уровне API
  • кэширование не применяется, поскольку хеширование всегда уникально для входных данных

Применение в распределённых системах

В системах с несколькими продуктами (web, mobile, internal tools) единый сервис хеширования позволяет:

  • унифицировать регистрацию пользователей
  • синхронизировать безопасность между платформами
  • упростить миграцию алгоритмов (например, переход bcrypt → argon2 через proxy-слой)

Версионирование алгоритма

При изменении параметров bcrypt важно поддерживать совместимость старых хешей.

Обычно хеш хранит информацию о версии:

$2a$12$...
$2b$10$...

Микросервис может:

  • автоматически определять версию
  • применять разные параметры при миграции
  • инициировать rehash при следующем входе пользователя

Итоговая архитектурная модель взаимодействия

  • API Gateway принимает запросы пользователей
  • Auth Service обрабатывает бизнес-логику
  • Hash Service выполняет bcrypt операции
  • Базы данных хранят только хеши, не пароли

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