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

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

Расписание ключей, SNI, ALPN и расширения

Суть Как HKDF выводит каждый ключ трафика из общего секрета, почему SNI раскрывает посещаемое имя хоста, и как ALPN, HelloRetryRequest и OCSP-прикрепление работают внутри рукопожатия.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на senior-высоте — в орбите
◷ 14 min

Вы понимаете, как ECDHE производит общий секрет. Но этот секрет не используется напрямую как ключ шифрования — он поступает в дерево выведения ключей, которое производит отдельные ключи для трафика рукопожатия, трафика приложения, возобновления и экспорта. Это дерево — расписание ключей HKDF, и каждый ключ, используемый TLS 1.3, вытекает из него.

Расписание ключей HKDF (RFC 8446 §7.1)

TLS 1.3 выводит каждый ключ из двухфазного дерева HKDF:

Фаза 1 — Early Secret.

early_secret = HKDF-Extract(salt=0, IKM=PSK_or_zero)

Если нет PSK: IKM — все нули. Из раннего секрета Derive-Secret(early_secret, "derived", "") производит соль для фазы 2.

Фаза 2 — Handshake Secret.

handshake_secret = HKDF-Extract(salt=derived_from_early, IKM=ECDHE_shared_secret)

Из секрета рукопожатия:

  • Ключ трафика клиента рукопожатия: HKDF-Expand-Label(hs_secret, "c hs traffic", transcript, hash_len)
  • Ключ трафика сервера рукопожатия: HKDF-Expand-Label(hs_secret, "s hs traffic", transcript, hash_len)

Фаза 3 — Master Secret.

master_secret = HKDF-Extract(salt=derived_from_handshake, IKM=zero)

Из мастер-секрета:

  • Ключ трафика приложения клиента: HKDF-Expand-Label(master, "c ap traffic", transcript, hash_len)
  • Ключ трафика приложения сервера: HKDF-Expand-Label(master, "s ap traffic", transcript, hash_len)
  • PSK возобновления: Derive-Secret(master, "res master", transcript)

Метки ("c hs traffic", "s ap traffic" и т.д.) — разделители доменов: компрометация одного пути вывода ключей не может помочь злоумышленнику на другом пути.

Расписание ключей HKDF в двух словах
Хэш для TLS_AES_128_GCM_SHA256
SHA-256
Хэш для TLS_AES_256_GCM_SHA384
SHA-384
Ключи трафика рукопожатия защищают
EncryptedExtensions → Finished
Ключи трафика приложения защищают
Все данные после Finished
Примитив обновления ключа
HKDF-Expand-Label(current, 'traffic upd', '', hash_len)
Набор шифров контролирует
Шифр AEAD + хэш для расписания; обмен ключами — отдельно

Разделение наборов шифров в TLS 1.3

TLS 1.2 упаковывал три выбора в одну строку набора шифров: обмен ключами, массовый шифр и MAC. TLS 1.3 разделил их:

  • Согласование именованных групп — выбирает кривую ECDHE (x25519, secp256r1, …)
  • Согласование алгоритмов подписи — выбирает способ верификации подписи сертификата (ecdsa_secp256r1_sha256, ed25519, …)
  • Набор шифров — выбирает только шифр AEAD и хэш для расписания ключей: TLS_AES_128_GCM_SHA256, TLS_CHACHA20_POLY1305_SHA256, TLS_AES_256_GCM_SHA384

В TLS 1.2 было сотни допустимых комбинаций. В TLS 1.3 — пять стандартных наборов.

SNI: указание имени сервера

Многие имена хостов разделяют один IP-адрес (виртуальный хостинг, CDN). Без дополнительной информации сервер не может выбрать правильный сертификат до чтения запроса — запрос зашифрован. SNI решает эту проблему, заставляя клиента отправлять имя хоста в открытом виде внутри ClientHello. Сервер использует его для выбора правильного сертификата перед ответом.

Цена конфиденциальности: любой в сети узнаёт, какой именно хост вы посетили. Это мотивация для Encrypted ClientHello (ECH), рассматриваемого в следующем уроке.

ALPN: согласование протокола прикладного уровня

После установки TLS клиент и сервер должны договориться о протоколе выше: HTTP/1.1, HTTP/2 или HTTP/3. ALPN помещает список в ClientHello (обычно ["h2", "http/1.1"]), и сервер выбирает один в ServerHello. Поскольку оба сообщения защищены хэшем транскрипта, промежуточный узел не может удалить h2, чтобы принудительно использовать HTTP/1.1 — вмешательство нарушает Finished.

HelloRetryRequest

Если key_share клиента содержит только кривую, которую сервер не поддерживает, сервер отправляет HelloRetryRequest (закодированный как специальный ServerHello со значением magic_retry_request_random), содержащий cookie и желаемую именованную группу. Клиент отправляет новый ClientHello с правильным key_share и cookie. Это добавляет один RTT, но встречается редко: современные клиенты предлагают x25519 и P-256 одновременно, чтобы предотвратить это. Cookie также позволяет серверам без сохранения состояния (балансировщикам нагрузки без привязки соединений) завершить HRR без сохранения состояния между двумя ClientHello.

OCSP-прикрепление и CRLite

Традиционный OCSP: клиент делает живой запрос к OCSP-ответчику CA для проверки отзыва — что раскрывает историю просмотров и добавляет задержку. OCSP-прикрепление переносит это на сервер: сервер периодически получает подписанный OCSP-ответ и прикрепляет его к TLS-рукопожатию через расширение status_request. Никакого дополнительного обращения клиента, никакой утечки конфиденциальности.

Реальность после 2024 года: Let’s Encrypt прекратил обслуживание OCSP 2025-05-07. Firefox 137 поставил CRLite по умолчанию — компактный, подписанный каскад фильтров Блума, охватывающий все отзывы WebPKI из журналов CT, обновляемый каждые 12 часов. Новая инфраструктура должна ориентироваться на 90-дневные (скоро 47-дневные) сроки жизни сертификатов вместо OCSP в реальном времени.

Прозрачность сертификатов (CT)

Каждый публично доверенный сертификат должен появляться как минимум в двух журналах CT — добавляемых только, публично проверяемых, подписанных деревьях Меркла. Клиент проверяет, что сертификат содержит Signed Certificate Timestamps (SCT). Chrome и Safari отклоняют соединения с отсутствующими или недействительными SCT. CT сделала экосистему CA проверяемой: недобросовестный CA не может выдать сертификат для example.com, не оставив публичной записи с защитой от фальсификации, а инструменты обнаружения (crt.sh) оповещают владельцев доменов в течение минут.

Викторина

Почему расписание ключей HKDF использует разделённые по домену метки для каждого ключа?

Викторина

Почему OCSP-прикрепление выводится из использования в WebPKI в 2024–2026 годах?

Расставь шаги по порядку

Упорядочите иерархию выведения ключей TLS 1.3 от входных данных до выходных:

  1. 1 Входные данные: общий секрет ECDHE
  2. 2 HKDF-Extract производит handshake secret
  3. 3 Derive-Secret производит секреты трафика рукопожатия (клиента и сервера)
  4. 4 HKDF-Expand-Label производит ключи трафика рукопожатия и IV
  5. 5 Записи под ключом трафика рукопожатия защищают EncryptedExtensions → Finished
  6. 6 После Finished: выводится master secret, производятся ключи трафика приложения
Почему это работает

Обновление ключа для долгоживущих соединений. TLS 1.3 поддерживает смену ключей трафика приложения в середине соединения без повторного согласования: любая из сторон отправляет KeyUpdate, выводит новый секрет трафика приложения через HKDF-Expand-Label(current, "traffic upd", "", hash_len) и начинает использовать новый ключ. Партнёр отвечает своим KeyUpdate. Современные шифры AEAD выдерживают огромные объёмы данных до того, как смена ключей становится критически важной для безопасности, но механизм существует для сверхдолгоживущих сессий (постоянные WebSocket-соединения, каналы сервисной сетки, открытые часами).

Вспомните перед уходом
  1. 01
    Как ALPN предотвращает атаки понижения версии HTTP?
  2. 02
    Какую информацию раскрывает SNI, и почему важен ECH?
  3. 03
    Когда TLS 1.3-сервер отправляет HelloRetryRequest, и что клиент обязан включить в повторный запрос?
Итог

Расписание ключей HKDF выводит дерево ключей из общего секрета ECDHE — ранний секрет, секрет рукопожатия, мастер-секрет — каждый разделён метками домена, так что компрометация одного пути не может помочь злоумышленнику на другом. TLS 1.3 также разделил согласование набора шифров на три независимые оси (именованная группа, алгоритм подписи, шифр AEAD), сократив сотни комбинаций TLS 1.2 до пяти стандартных наборов. SNI отправляет целевое имя хоста в открытом виде для работы виртуального хостинга; ALPN согласовывает протокол приложения над TLS внутри защищённого от вмешательства транскрипта. HelloRetryRequest обрабатывает крайний случай, когда первое предположение клиента о key_share неверно. OCSP-прикрепление снижало задержку проверки отзыва для каждого соединения; CRLite (Firefox 137+) заменяет его каскадом фильтров Блума с локальным обновлением.

Связанные уроки
встречается в47
Продолжить восхождение ↑Защита 0-RTT, ECH, гибридный PQ и продакшн TLS
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources4
expand
  1. 01
  2. 02
  3. 03
  4. 04

Trademarks belong to their respective owners. Editorial reference only.