Инженерный разбор: где находится точка контроля и почему это выглядит как необъяснимый разрыв.

Почему HTTPS обрывается сразу после соединения: DPI, SNI и момент ClientHello

Сетевая картина часто выглядит парадоксально: IP доступен, порт 443 отвечает, TCP-рукопожатие проходит без единой ошибки — а затем соединение мгновенно «падает» в тот самый момент, когда браузер отправляет первые данные поверх установленного канала. Такое поведение редко связано с «капризами» удалённого сервера. Чаще это эффект работы промежуточных устройств, которые принимают решение уже после того, как видят конкретный фрагмент протокола.

В: Как устроена цепочка TCP → TLS → HTTP и где чаще всего происходит сбой?

Упростим до последовательности шагов. Она нужна, чтобы точно понимать: на каком этапе у фильтра появляется достаточно данных для классификации соединения.

  • 1. TCP (3-way handshake) SYN → SYN-ACK → ACK. Транспортный канал поднят, никакого HTTPS ещё нет — это просто TCP-сессия.
  • 2. TLS браузер отправляет ClientHello, чтобы согласовать версию протокола, наборы шифров и параметры, необходимые для защищённого канала.
  • 3. HTTP лишь после завершения TLS-рукопожатия уходят HTTP-запросы — уже внутри шифрованного туннеля.
Цепочка TCP → TLS → HTTP
Цепочка TCP → TLS → HTTP

В: Если всё шифруется, откуда DPI знает, какой домен вы открываете?

DPI (Deep Packet Inspection) пытается определить назначение соединения не только по IP/портам, но и по содержимому пакетов. Проблема для DPI в том, что основная часть трафика сегодня — это TLS 1.3 и HTTPS, то есть «шум» для наблюдателя.

Однако у TLS есть исторический компромисс: в самом начале рукопожатия клиент должен сообщить серверу, к какому имени он обращается, чтобы корректно выбрать сертификат и конфигурацию. Для этого долгое время использовалось расширение SNI (Server Name Indication), которое находится в ClientHello.

Важно: в TLS 1.3 ClientHello всегда содержит extensions (например, supported_versions). Это делает ClientHello стабильной и предсказуемой «точкой наблюдения» — удобно для сигнатурной логики на стороне DPI, потому что структура сообщения ожидаема.

В: Почему соединение обрывается именно после ClientHello?

На практике встречаются два типовых сценария. Они отличаются тем, стоит ли устройство в разрыве канала или работает «в стороне».

  • Пассивное наблюдение + инжект устройство анализирует поток и при совпадении с сигнатурой отправляет поддельный управляющий пакет (например, RST/FIN), имитируя поведение сервера.
  • Активная фильтрация on-path устройство находится на пути трафика и может напрямую блокировать прохождение отдельных пакетов, не допуская нормального продолжения TLS.

В обоих случаях момент «срабатывания» логичен: TCP уже установлен, а вот ClientHello — это первый этап, где появляется полезный сигнал для классификации.

В: Как отличить «сервер сбросил» от «сбросили посередине»?

Железобетонного одного признака нет, но есть набор индикаторов, которые вместе дают уверенную картину. Самый популярный — сравнение TTL: поддельный пакет часто «слишком близкий» по числу хопов по сравнению с реальными ответами удалённого сервера.

  • TTL сравните TTL пакета, который завершает сессию, с TTL обычного трафика от сервера.
  • TCP-почерк window size, TCP options (SACK, window scaling), поведение seq/ack — подделки нередко расходятся с тем, как ведёт себя настоящий стек.
  • Время и «гонки» при пассивной инъекции поддельный RST должен успеть прийти «раньше» полезного ответа. На таймингах часто видно вмешательство.

В: Почему DPI путается из-за out-of-order, overlap и tiny segments?

Здесь нет мистики — есть разница ролей. Конечные устройства собирают поток строго по правилам своего TCP/IP стека. DPI же вынужден работать на огромной пропускной способности и часто использует упрощённую модель сборки данных.

Если endpoint и middlebox восстанавливают разные версии байтового потока (из-за переупорядочивания, неоднозначностей перекрытий или слишком мелкой сегментации), сигнатура может «не сложиться» у DPI, хотя сервер при этом увидит корректные данные.

Именно поэтому метафора «вахтёра с короткой памятью» здесь уместна: полноценная stateful-сборка для миллионов параллельных соединений стоит дорого, и компромиссы создают зазоры.

В: Почему подходы из мира TCP плохо переносятся на HTTP/3 и QUIC?

HTTP/3 — это HTTP поверх QUIC. А QUIC — транспорт поверх UDP со своей моделью состояния и криптографией. Многие приёмы, которые опираются на особенности TCP (границы сегментов, поведение окон, специфические поля), для QUIC напрямую неприменимы.

Проще говоря: если метод «заточен» под манипуляции TCP-механикой, то на QUIC он упирается в другой транспорт и другую видимость.

В: ECH — «будущее, которое уже частично в проде»?

Да. ECH (Encrypted ClientHello) шифрует чувствительную часть ClientHello, включая то, что ранее раскрывалось через SNI-подобные сигналы. Для DPI это означает потерю простого способа прочитать имя домена на старте TLS.

Практические детали, которые важно понимать:

  • Firefox включает ECH по умолчанию Firefox включает ECH по умолчанию (если инфраструктура назначения это поддерживает).
  • Крупные CDN Крупные CDN (например, Cloudflare) описывают ECH как способ скрыть SNI от наблюдателей.
  • ECH Для ECH критична доставка конфигурации — часто через SVCB/HTTPS DNS записи. Если конфигурация не доезжает, «волшебства» не произойдёт.
ECH и исчезновение SNI-сигнала
ECH и исчезновение SNI-сигнала

В: Как это выглядит на уровне реализации: WinDivert vs NFQUEUE?

Инженерно всё сводится к тому, где перехватываются пакеты и как принимается решение об их дальнейшей судьбе.

  • Windows Часто применяют WinDivert: драйверный перехват, который позволяет в user-mode захватывать пакеты, применять правила, модифицировать и реинжектить обратно в сетевой стек.
  • Linux В роутерных/серверных сценариях распространён NFQUEUE: Netfilter отправляет пакеты в очередь userspace-программе, а та возвращает в ядро вердикт (accept/drop и т.п.) после анализа/изменения.

Быстрый чеклист для Wireshark

Если нужно быстро понять «где ломается», снимите дамп и пройдитесь по пунктам:

  • 1. Есть ли чистый SYN/SYN-ACK/ACK и затем ClientHello?
  • 2. Что завершает сессию: RST, FIN или тишина (drop/timeout)?
  • 3. Совпадают ли TTL и TCP options «пакета-убийцы» с почерком сервера?
  • 4. Событие привязано именно к ClientHello, а не к поздним данным?
  • 5. Меняется ли поведение при переходе между HTTP/2 (TCP) и HTTP/3 (QUIC)?

Примечание: этот материал — про устройство протоколов и работу middlebox’ов. Для диагностики и тестов используйте сети и окружения, где у вас есть полномочия, и опирайтесь на легитимные инструменты защиты приватности и безопасности.