TLS 1.3 по-прежнему отправляет имя сервера открытым текстом
TLS 1.3 шифрует рукопожатие, но не SNI. Прочитайте ClientHello, проверьте настоящее принятие ECH и зафиксируйте, что наблюдатель всё ещё может видеть.
Обновление слушателя до TLS 1.3 меняет то, что наблюдатель может прочитать, но не настолько, насколько предполагает номер версии. ClientHello по-прежнему передаётся до согласования любого шифрования, и в обычном соединении запрошенное имя сервера находится там открытым текстом. Encrypted Client Hello — это механизм, который его скрывает, и это отдельное развёртывание со своими предпосылками. Выполните эти четыре шага, прежде чем писать политику, предполагающую любое из двух поведений.
Что рукопожатие действительно раскрывает
TLS 1.3 шифрует сертификат сервера и большую часть рукопожатия, следующего за ServerHello. Всё, что клиент отправляет первым, остаётся вне этой защиты, потому что ключей ещё не существует. Указание имени сервера входит в этот первый полёт, поэтому пассивный наблюдатель всё ещё может его прочитать, ничего не взламывая.
Спецификация ECH, RFC 9849, меняет это, шифруя внутренний ClientHello для сотрудничающего сервера. Внешнее рукопожатие сохраняется и несёт публичное имя, которое видит сеть, поэтому развёртыванию по-прежнему нужна внешняя идентичность, понятная посредникам. Это внешнее имя — та часть, которую люди упускают, ожидая, что соединение станет анонимным. Это прикрывающее имя, а не скрытое, и оно должно разрешаться и аутентифицироваться как любое другое.
Ничто из этого не скрывает путь доставки. Исходные и целевые адреса, порты, размеры пакетов и тайминги остаются наблюдаемыми, и они часто говорят о том, кто говорит, больше, чем имя. Разрешение имён и связи на уровне приложений — ещё один слой, каждый со своей видимостью.
Читайте ClientHello вместо предположений
Версия в ServerHello не говорит, что отправил клиент. Посмотрите на первый полёт напрямую, с позиции, представляющей интересующего вас наблюдателя.
openssl s_client -connect app.plant.example:443 -servername app.plant.example -tls1_3 </dev/null> 2>/dev/null | head -20 sudo tcpdump -ni eth0 -c 40 'tcp port 443' -w /tmp/tls.pcap tshark -r /tmp/tls.pcap -Y 'tls.handshake.extensions_server_name' -T fields -e tls.handshake.extensions_server_name
Первая команда выполняет рукопожатие и показывает согласованные параметры, включая версию протокола и запрошенное вами имя. Вторая захватывает первые пакеты реального соединения, а третья извлекает поле SNI из этого захвата. Если поле заполнено, эмулируемый вами наблюдатель может его прочитать.
Захватывайте отдельно на стороне клиента и на пути, когда эти два не совпадают, потому что локальный захват может показать имя, которое промежуточное устройство позже перепишет или отбросит. Захватывайте также с хоста, который сам не завершает TLS, поскольку завершающий прокси видит открытый текст по своей конструкции и ничего не доказывает о том, что видит сеть.
Относитесь к расширению ECH как к утверждению, а не доказательству
Обнаружение расширения ECH в ClientHello не означает, что соединение использовало ECH. Клиенты отправляют GREASE ECH, когда у них нет пригодной конфигурации, именно для того, чтобы их рукопожатия выглядели одинаково. Расширение присутствует, внутренний hello — приманка, а настоящее имя по-прежнему читается.
dig +short HTTPS app.plant.example openssl s_client -connect app.plant.example:443 -tls1_3 -status </dev/null> 2>/dev/null | grep -i -E 'ech|status_request'
Первая команда показывает, публикует ли источник запись ресурса HTTPS с параметром конфигурации ECH, и именно так клиенты узнают ключ. Вторая ищет сведения о состоянии рукопожатия, хотя сообщение об успехе клиента — более сильное доказательство. Важно принятие: сервер без подходящего ключа не может расшифровать внутренний hello, и соединение откатывается.
Проверьте и клиент, поскольку поддержка браузеров и конфигурация различаются по версии и платформе. Политика, построенная на „современные браузеры используют ECH“, — это догадка о парке, а не факт о вашем парке. Проведите инвентаризацию версий, которые действительно подключаются, и протестируйте по одной из каждой. Та же страница, работающая из актуального настольного браузера, может ничего не скрыть от более старого клиента в той же сети.
Запишите область наблюдателя в политику
Укажите, где находится наблюдатель и что видно в этой точке, прежде чем решать, на что может опираться контроль. Соединение браузера с сайтом, внешний транспорт VPN и прокси, завершающий TLS, раскрывают каждый свой набор фактов, и правило, написанное для одной позиции, редко переносится чисто на другую.
Если контроль зависит от чтения SNI, проверьте, как ведут себя развёрнутые клиенты, когда ECH доступен и когда нет. Затем зафиксируйте последствие для совместимости, потому что фильтр, который молча перестаёт совпадать, хуже того, который никогда не развёртывался.
Наконец, сохраняйте неопределённость в запись. Замена старого универсального утверждения более новым оставляет тот же пробел под другим именем протокола, и следующий рецензент поверит в него так же твёрдо.