Перехват пароля до хеширования: угрозы на транспортном уровне

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

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


Транспортный уровень и границы доверия

Передача данных между клиентом и сервером происходит через сетевые протоколы. В современных веб-приложениях это почти всегда HTTP поверх TLS (HTTPS). TLS создаёт защищённый канал, в котором данные шифруются до передачи и расшифровываются только на стороне получателя.

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

Граница доверия в системе проходит не через базу данных и не через bcrypt, а через момент установления защищённого соединения.


Перехват пароля на транспортном уровне

Передача по HTTP

Самая базовая уязвимость — использование обычного HTTP. В этом случае любые промежуточные узлы сети могут видеть тело запроса целиком, включая пароль.

Типичные сценарии перехвата:

  • публичные Wi-Fi сети
  • корпоративные прокси без TLS-терминации
  • вредоносные маршрутизаторы
  • заражённые устройства в локальной сети

Man-in-the-Middle (MITM)

Атака типа MITM позволяет злоумышленнику вставать между клиентом и сервером. В зависимости от условий сети он может:

  • читать трафик
  • изменять содержимое запросов
  • подменять ответы сервера

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


SSL stripping

Даже при наличии HTTPS возможен сценарий понижения уровня защиты. Злоумышленник перехватывает первоначальный HTTP-запрос и не позволяет клиенту перейти на HTTPS, подменяя ссылки или перенаправления.

Без механизмов принудительного HTTPS (например, HSTS) пользователь может даже не заметить, что соединение осталось незащищённым.


DNS-атаки и подмена маршрута

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


Почему bcrypt.js не защищает транспортный уровень

bcrypt.js решает задачу хранения и проверки паролей, а не их передачи.

Его свойства:

  • устойчивость к brute-force атакам
  • адаптивная стоимость вычислений
  • невозможность восстановить исходный пароль из хеша

Но ни одно из этих свойств не помогает, если пароль был украден до хеширования.

Если злоумышленник получает пароль до выполнения bcrypt.hash, он получает исходный секрет в чистом виде и может:

  • авторизоваться напрямую
  • использовать его повторно в других сервисах
  • обойти любые механизмы защиты хранилища

Ошибка: попытка хешировать пароль на клиенте

Иногда появляется идея выполнить bcrypt.hash на стороне браузера и отправлять уже хеш.

Проблема в том, что:

  • хеш становится эквивалентом пароля
  • злоумышленник, перехватив хеш, может использовать его как пароль (replay-атака)
  • отсутствует соль, привязанная к серверному контексту
  • нарушается модель аутентификации

bcrypt не предназначен для замены защищённого канала связи.


Корректная модель: TLS как обязательный слой

Безопасная архитектура предполагает последовательность:

  1. Клиент вводит пароль
  2. Данные передаются только через HTTPS
  3. Сервер получает пароль
  4. bcrypt.js хеширует пароль
  5. хеш сохраняется в базе данных

Пример серверной проверки:

import bcrypt from "bcryptjs";

async function login(req, res) {
  const { password, user } = req.body;

  const hashFromDb = user.passwordHash;

  const isValid = await bcrypt.compare(password, hashFromDb);

  if (!isValid) {
    return res.status(401).send("Invalid credentials");
  }

  return res.status(200).send("OK");
}

В этой модели bcrypt используется только внутри доверенной серверной зоны.


HSTS и принудительное шифрование канала

Одного включённого HTTPS недостаточно. Важно исключить возможность первого незащищённого запроса.

HTTP Strict Transport Security (HSTS) решает эту проблему:

  • браузер запоминает необходимость HTTPS
  • любые попытки перейти по HTTP блокируются автоматически
  • исключается SSL stripping на уровне клиента

Промежуточные узлы и утечки до bcrypt

Даже при HTTPS существуют зоны риска внутри инфраструктуры:

Reverse proxy

Если TLS завершается на прокси (Nginx, Cloudflare, балансировщик), то внутри сети пароль может передаваться в открытом виде между сервисами.

Логирование запросов

Ошибки конфигурации приводят к тому, что тела POST-запросов попадают в:

  • access-логи
  • системы мониторинга
  • APM-инструменты

Это создаёт отдельный канал утечки, не связанный с bcrypt.js.

Инструменты аналитики

Некоторые системы трассировки могут случайно захватывать payload запросов, включая пароли, если не настроены фильтры маскирования.


Разделение ответственности: транспорт против хранения

Система аутентификации состоит из двух независимых уровней:

Транспортный уровень

  • TLS/HTTPS
  • защита от MITM
  • контроль сертификатов
  • HSTS

Уровень хранения

  • bcrypt.js
  • соль и cost factor
  • защита базы данных
  • сравнение хешей

Ошибка возникает, когда эти уровни смешиваются и bcrypt воспринимается как универсальная защита пароля на всех этапах.


Практическая модель угроз

Если рассматривать жизненный цикл пароля:

  1. Ввод на клиенте — уязвимость №1
  2. Передача по сети — уязвимость №2
  3. Обработка сервером — контролируемая зона
  4. Хранение — защищается bcrypt.js

Любая компрометация на первых двух этапах делает последующие меры защиты несущественными.


Поведение системы при компрометации канала

При успешном перехвате на транспортном уровне:

  • bcrypt.js не фиксирует факт атаки
  • база данных остаётся неизменной
  • система не отличает легитимный ввод от украденного

Это делает транспортный уровень критическим элементом всей модели безопасности, а не вспомогательной опцией.