awesome-everything EN
↑ Обратно к восхождению

Сети и протоколы

Защита 0-RTT, ECH, гибридный PQ и продакшн TLS

Суть Продакшн-защиты от повтора 0-RTT, ротация STEK в масштабах CDN, Encrypted ClientHello, гибридный постквантовый обмен ключами, выгрузка kTLS в ядро и метрики наблюдаемости для любого TLS-сервиса.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на senior-высоте — в орбите
◷ 16 min

FinTech-сервис, обрабатывающий 50 тысяч TLS-рукопожатий в секунду, не может позволить себе наивно включённый 0-RTT, статический ключ сессионного тикета или чисто классический обмен ключами, который будущий квантовый компьютер способен ретроспективно взломать. Этот урок — о том, как продакшн-развёртывания защищаются от повтора, ротируют STEK, скрывают SNI через ECH, добавляют постквантовую защиту и наблюдают за TLS в масштабе.

Защита от повтора 0-RTT в продакшне (RFC 8446 §8 + RFC 8470)

Три ортогональных защиты применяются в совокупности:

1. Валидация возраста тикета. Клиент отправляет obfuscated_ticket_age; сервер вычитает ticket_age_add, учитывает ожидаемый RTT и отклоняет early_data, если результат выходит за пределы узкого окна (типично: 10 с). Злоумышленник, воспроизводящий данные часы спустя, получает немедленный отказ.

2. Однократное использование тикета. Кэш в памяти с ключом (ticket_nonce, age_bucket) отклоняет любую вторую попытку расшифровки. Cloudflare ведёт кэши на каждой точке присутствия плюс best-effort кросс-PoP синхронизацию, чтобы повторы между регионами также перехватывались в пределах окна.

3. Идемпотентность на уровне приложения. Только безопасные методы проходят в early_data. Фреймворки (Spring, Express, Caddy) проверяют заголовок запроса Early-Data: 1 и возвращают 425 Too Early для любого обработчика, изменяющего состояние.

Ротация ключа шифрования сессионных тикетов (STEK)

Без прямой секретности при возобновлении утечка STEK позволяет злоумышленнику расшифровать все 0-RTT-данные из тикетов, выданных этим ключом. Правила для продакшна:

  • Ротируйте не реже раза в час (Cloudflare ротирует ежечасно; операторы Nginx должны перезагружаться с новым ssl_session_ticket_key в начале очереди).
  • Держите кольцевой буфер из прежних ключей только для расшифровки (обычно 24 ключа), чтобы тикеты в пути продолжали возобновляться.
  • Никогда не сохраняйте STEK на диск. Хранение только в памяти — обязательное требование.
  • Распространяйте новые ключи на все бэкенды через аутентифицированное распределение до истечения старого ключа, чтобы кросс-узловые тикеты оставались возобновляемыми.

Режимы отказа: ключи, сохранённые на диск и восстановленные после компрометации узла (инцидент GoDaddy 2023); статический STEK, настроенный на год, превращающий возобновление в монокультуру одного ключа.

Encrypted ClientHello (ECH, RFC 9849)

Обычный ClientHello в TLS 1.3 раскрывает SNI, ALPN, поддерживаемые группы и алгоритмы подписи — достаточно для идентификации целевого имени хоста и стека клиента. ECH (RFC 9849, опубликован в марте 2026) определяет:

  • Внешний ClientHello, отправляемый на публичное имя хоста фронтенда.
  • Внутренний ClientHello, зашифрованный через HPKE с использованием опубликованного ECH-ключа источника (полученного из DNS-записи HTTPS/SVCB, RFC 9460).

Клиент получает ECH-ключ до TCP-соединения. Если он недоступен, клиент может использовать GREASE (отправить фиктивный ECH) или откатиться к обычному SNI. Chrome поставляет ECH по умолчанию начиная с Chrome 117+; Firefox включил его с версии 119; поддержка Safari всё ещё в разработке по состоянию на май 2026 года.

Операторы должны регулярно ротировать публичный ECH-ключ (TTL DNS — верхняя граница компрометации ключа) и принять, что внешний SNI по-прежнему называет общий фронтенд.

Гибридный постквантовый обмен ключами

draft-ietf-tls-ecdhe-mlkem (февраль 2026) стандартизирует X25519MLKEM768 (кодовая точка именованной группы 0x11EC). ML-KEM — это NIST FIPS 203 (стандартизирован в августе 2024). Гибридный общий секрет:

combined_secret = concat(ecdhe_secret, mlkem_secret)

Это поступает в HKDF-Extract там, где раньше находился классический секрет ECDHE — расписание ключей ниже не изменяется. Гибрид безопасен, если держится хотя бы один примитив: квантовый компьютер, взломавший ECDHE, не сможет восстановить сессию, если ML-KEM устоит.

Стоимость на уровне протокола: публичные ключи ML-KEM-768 занимают 1184 байта, шифртексты — 1088 байт, что вынуждает ClientHello превысить 1500 байт и требует TCP-сегментации. Chrome 131+ (ноябрь 2024) поставляет гибридный PQ по умолчанию. По состоянию на Q1 2026 более трети трафика Cloudflare использует гибридные PQ-рукопожатия.

Стоимость гибридного PQ-обмена ключами
Публичный ключ X25519
32 байта
Публичный ключ ML-KEM-768
1 184 байта
Шифртекст ML-KEM-768
1 088 байт
Размер гибридного ClientHello
>1 500 байт (TCP-сегментация)
Chrome по умолчанию с
Chrome 131 (ноябрь 2024)
Трафик Cloudflare на гибридном PQ (Q1 2026)
>33%

Ядерный TLS (kTLS) — выгрузка в ядро

setsockopt(fd, SOL_TLS, TLS_TX, &crypto_info) передаёт симметричный уровень записи ядру после завершения рукопожатия в пользовательском пространстве (Linux 4.13+, OpenSSL 3.2+). Современные ядра плюс поддерживаемый сетевой адаптер могут строить зашифрованные записи прямо на проводе с нулевой CPU-стоимостью на запись.

Netflix и Cloudflare приписывают экономию 8–29% CPU при обслуживании статических файлов использованию sendfile() поверх kTLS: файл перемещается из кэша страниц на сетевой адаптер, не попадая в пользовательское пространство. Поддерживаемые алгоритмы: AES-128-GCM, AES-256-GCM, ChaCha20-Poly1305 — только TLS 1.3.

Вмешательство промежуточных узлов и GREASE (RFC 8701)

TLS 1.3 помещает 0x0303 (TLS 1.2) в поле legacy_version и отправляет фиктивную запись ChangeCipherSpec, поскольку слишком много промежуточных узлов прерывают соединения, байты которых не соответствуют шаблонам TLS 1.2. GREASE (RFC 8701) рассыпает зарезервированные кодовые точки (0x0A0A, 0x1A1A, …, 0xFAFA) по спискам расширений и наборам шифров. Корректный партнёр игнорирует неизвестные значения; хрупкий промежуточный узел ломается немедленно, обнажая ошибку перед поставщиком вместо того, чтобы дать ей окаменеть в протоколе.

Наблюдаемость в продакшне

Минимально жизнеспособный набор метрик Prometheus для TLS-сервиса:

  • tls_handshake_duration_seconds_bucket — гистограмма; p95 выше 200 мс на CDN-источнике — это регрессия.
  • tls_resumption_total{kind="psk|ticket|none"} — резкое падение доли возобновлений обычно означает ротацию STEK без окна перекрытия.
  • tls_version_total{version="1.2|1.3"} — помечайте любой трафик на 1.2.
  • tls_cipher_suite_total — выявляйте нежелательные наборы шифров.
  • tls_early_data_total{outcome="accepted|rejected"} — всплеск отклонений early_data нередко предшествует сообщениям клиентов о дублирующихся POST.
  • tls_ocsp_staple_total{outcome="ok|expired|missing"} — отсутствие прикрепления на сертификате с must-staple вызовет отказы соединений.

Реальные производственные инциденты

  • Истечение цепочки Let’s Encrypt 2021: срок действия DST Root CA X3 истёк; Android < 7.1.1 не прошёл верификацию, сломав длинный хвост устройств.
  • Утечка STEK GoDaddy 2023: утечка STEK в неправильно настроенной резервной копии клиента позволила злоумышленнику расшифровать месяцы кэшированных данных 0-RTT — именно тот режим отказа, о котором предупреждает RFC 8446 §2.3.
  • Heartbleed (CVE-2014-0160): отсутствующая проверка длины в расширении heartbeat OpenSSL позволяла злоумышленникам читать 64 КБ памяти процесса, включая приватные ключи. Постмортем изменил экосистему (BoringSSL, rustls) и является причиной, по которой kTLS ограничивает поверхность ядра только шифрованием уровня записи.
Проследи
1/3

Гибридное рукопожатие ML-KEM-768 + x25519 (Chrome 131+)

1
Step 1 of 3
Клиент отправляет публичный ключ x25519 + публичный ключ ML-KEM-768 в key_share. Какое свойство безопасности это обеспечивает?
2
Locked
Старый сервер не распознаёт именованную группу ML-KEM-768. Что происходит?
3
Locked
Почему гибридный PQ вынуждает TCP-сегментацию в большинстве соединений?
Найди ошибку

Ошибка рукопожатия OpenSSL — определите причину.

log
% openssl s_client -connect api.example.internal:443 -tls1_3 -showcerts
CONNECTED(00000005)
depth=0 CN = api.example.internal
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN = api.example.internal
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
0 s:CN = api.example.internal
 i:CN = Internal Corp Issuing CA
---
SSL handshake has read 1845 bytes and written 308 bytes
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server certificate
subject=CN = api.example.internal
issuer=CN = Internal Corp Issuing CA
---
SSL-Session:
  Protocol  : TLSv1.3
  Verify return code: 21 (unable to verify the first certificate)

Рукопожатие завершается, но verify return code = 21. В чём неправильная конфигурация и что сервер должен отправлять для исправления?

Викторина

Почему утечка STEK позволяет расшифровывать данные 0-RTT, но не обычные рукопожатия TLS 1.3?

Почему это работает

mTLS в масштабах сервисной сетки. Istio + SPIFFE/SPIRE выдают свежие листовые сертификаты на каждую рабочую нагрузку (TTL нередко менее 24 часов), ротируя через API рабочей нагрузки SPIRE. При 10 000 подов с 24-часовой ротацией это примерно 7000 выдач сертификатов в минуту. CA уровня управления становится узким местом; иерархическая конструкция CA (корневой → промежуточный на кластер) держит подписание листов внутри кластера и делает его быстрым. Плоскость данных (Envoy) завершает и переинициирует TLS на каждом переходе — ваш бюджет сквозной задержки оплачивает рукопожатие TLS 1.3 на каждой границе сервиса, если только пулы соединений не амортизируют стоимость на тысячи запросов.

Вспомните перед уходом
  1. 01
    Назовите три ортогональные защиты от повтора 0-RTT и что каждая из них перехватывает.
  2. 02
    Почему гибридный PQ конкатенирует секреты ECDHE и ML-KEM, а не использует только один из них?
  3. 03
    Какая продакшн-метрика наиболее прямо сигнализирует об ошибке ротации STEK?
Итог

Безопасность 0-RTT в продакшне требует трёх послойных защит: окно повтора по возрасту тикета, кэш одноразовых nonce на точку присутствия и 425 Too Early на уровне приложения для неидемпотентных маршрутов. Ключи шифрования сессионных тикетов должны ротироваться не реже раза в час, никогда не касаться диска и распределяться на все бэкенды до истечения старого ключа. Encrypted ClientHello (RFC 9849) скрывает целевой SNI от наблюдателей на пути; гибридный PQ (X25519MLKEM768) защищает от квантовых атак «записывай сейчас — расшифровывай потом» ценой увеличения ClientHello. Ядерный TLS выгружает симметричный уровень записи на сетевой адаптер, давая 8–29% экономии CPU при обслуживании статических файлов. Минимально жизнеспособный набор метрик отслеживает p95 продолжительности рукопожатия, долю возобновлений, исходы early_data и распределение наборов шифров — падение доли возобновлений является самым быстрым сигналом об ошибке ротации STEK.

Связанные уроки
встречается в47
Продолжить восхождение ↑TLS 1.3: обзор с выбором ответа
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources8
expand
  1. 01
  2. 02
  3. 03
  4. 04
  5. 05
  6. 06
  7. 07
  8. 08

Trademarks belong to their respective owners. Editorial reference only.