ЛИСТ B-04 · ПУБЛИКАЦИЯ
ARTICLE
← Назад к блогу

Разделение TLS-трафика по SNI: как запустить два сервиса на одном порту 443

5 мин. чтения0 просмотров#Tls#Nginx#безопасность сети#Infrastructure Security

Разделение TLS-трафика по SNI: как запустить два сервиса на одном порту 443

Представьте стандартную для многих инфраструктур ситуацию: у вас есть один публичный IP-адрес, на котором уже работает критически важный веб-сервис. Внезапно возникает задача развернуть второй независимый TLS-приложение (например, корпоративный VPN или отдельный API-шлюз), но при этом менять настройки DNS или заставлять пользователей перенастраивать свои клиенты невозможно. Классический конфликт портов кажется неразрешимым, однако протокол TLS предоставляет элегантное решение через механизм Server Name Indication (SNI). Этот параметр передаётся клиентом в самом начале сессии, в открытом тексте сообщения ClientHello, ещё до установления зашифрованного канала.

Механизм работы SSL-пререндинга в Nginx

Для решения задачи разделения трафика без расшифровки сессий идеально подходит режим прозрачного проксирования в Nginx. Традиционно Nginx выступает терминатором TLS, то есть он завершает шифрование, читает HTTP-заголовки и затем пересылает трафик бэкенду. В нашем случае это неприемлемо, так как мы не хотим управлять сертификатами всех сервисов в одной точке. Вместо стандартной директивы proxy_pass используется блок stream вместе с модулем ngx_stream_ssl_preread_module.

Конфигурация выглядит следующим образом: Nginx слушает внешний порт 443, считывает значение из поля server_name пакета ClientHello с помощью функции ssl_preread_server_name и на основе этого значения маршрутизирует TCP-соединение на нужный внутренний адрес. Важно понимать, что сам Nginx никогда не видит ключей шифрования и не расшифровывает данные — он работает исключительно на уровне четвёртого транспортного уровня, анализируя только приветственное сообщение TLS. Это позволяет сохранить сквозное шифрование между конечным пользователем и целевым сервисом.

Архитектурные риски и проблема реальных IP-адресов

За прозрачность такого решения приходится платить потерей видимости клиентских адресов на стороне бэкенда. Поскольку Nginx пробрасывает соединение «как есть» после первого пакета, целевой сервер получает в качестве источника IP-адрес самого балансировщика (Nginx), а не реального пользователя. Для логирования аудита, систем предотвращения вторжений (IPS) и механизмов ограничения скорости (rate limiting) это создаёт серьёзную проблему.

Обычно эта проблема решается внедрением протокола PROXY (PROXY protocol v1/v2), который добавляет небольшой бинарный заголовок поверх TCP-соединения, содержащий исходные IP и порты. Однако здесь кроется ловушка: ваш конечный сервис (бэкенд) должен уметь корректно обрабатывать этот дополнительный заголовок. Если вы пытаетесь направить трафик на стандартный Apache или старое приложение, которое не знает о PROXY protocol, соединения будут просто разрываться с ошибкой Handshake Failure. Таким образом, архитектура требует синхронной поддержки данного протокола на всём пути следования трафика.

Критическая роль ветки default и отказоустойчивость

Любая конфигурация маршрутизации по SNI опирается на наличие блока по умолчанию (default_backend). Что произойдёт, если пользователь обратится к вашему IP напрямую по IP-адресу, не указывая имя хоста? Или если злоумышленник просканирует ваши поддомены методом перебора? Пакет ClientHello придёт со значением server_name равным NULL или неизвестному имени. Без явной ветки default такой запрос либо будет сброшен, либо приведёт к непредсказуемому поведению службы.

Правильная практика безопасности диктует отправлять весь «мусорный» или неопределённый трафик на специальный изолированный эндпоинт. Это может быть легковесная заглушка, которая всегда возвращает ошибку 404 на уровне TLS, или система-ловушка (honeypot) для анализа активности сканеров. Отсутствие дефолтного маршрута делает вашу инфраструктуру уязвимой к раскрытию информации о внутренних именах хостов через дифференциацию ответов сервера.

Будущее технологии и влияние ECH (Encrypted Client Hello)

Текущая модель работы имеет вполне обозримый срок годности, обусловленный развитием стандартов приватности. Инициатива Encrypted Client Hello (ECH), продвигаемая сообществом IETF и компаниями вроде Cloudflare и Mozilla, призвана закрыть последний оставшийся вектор утечки данных в TLS — тот самый открытый текст SNI в ClientHello. Как только браузеры и серверы массово перейдут на TLS 1.3 с включённым ECH, поле server_name будет зашифровано ключом провайдера публичных записей DNS.

В этой ситуации Nginx физически не сможет прочитать имя хоста до момента завершения TLS handshake. Прозрачное проксирование по SNI перестанет работать в его текущем виде. Организациям придётся переходить на более сложные схемы: использование различных ALPN (Application-Layer Protocol Negotiation) внутри одного порта, разворачивание полноценного Service Mesh или возврат к использованию разных внешних IP-адресов для каждого сервиса. Начинать планировать миграцию стоит уже сейчас, особенно если ваша стратегия рассчитана на 3–5 лет вперёд.

Практические шаги для внедрения

Если вам необходимо реализовать подобную схему сегодня, следуйте строгому алгоритму проверки:

  • Проверьте версию Nginx: модуль ssl_preread доступен начиная с версии 1.11.5, убедитесь, что он собран статически (--with-stream_ssl_preread_module).
  • Настройте передачу реальных IP через PROXY protocol на всех принимающих серверах и обновите их конфигурации для чтения этих заголовков.
  • Выделите отдельный backend-блок для обработки запросов без указания SNI (дефолтный маршрут) и направляйте его на изолированную систему мониторинга.
  • Протестируйте поведение системы при обращении к ресурсу по прямому IP-адресу, чтобы исключить утечку баннеров версий ПО.
  • Заложите в архитектуру возможность горизонтального масштабирования самих бэкендов, так как Nginx в режиме stream не выполняет L7-балансировку.

Как проверить с помощью Perimeter Платформа External Attack Surface Management (EASM) поможет убедиться, что ваша сложная схема маршрутизации не создала новых дыр. Используйте модуль network scanning для инвентаризации открытых портов и сопоставления имён хостов. Инструмент TLS scanner проверит корректность цепочек сертификатов на каждом из скрытых бэкендов, доступ к которым осуществляется через SNI-маршрутизацию. Кроме того, мониторинг изменений позволит мгновенно обнаружить, если кто-то из администраторов случайно изменит конфиг Nginx и сделает внутренние сервисы общедоступными без должной изоляции.

Поделиться:TelegramVK

Похожие статьи

Мы используем файлы cookie для обеспечения работоспособности сервиса и улучшения качества обслуживания. Продолжая использовать сайт, вы соглашаетесь с политикой конфиденциальности.