TLS handshake по шагам: что происходит за 100 миллисекунд до загрузки сайта
Полный разбор первого диалога браузера и сервера: версии, ключи, сертификаты, RTT
Откройте F12 на любом современном сайте и посмотрите вкладку Network. Рядом с временем ответа почти каждого ресурса есть полоска SSL/TLS — те самые 30–150 миллисекунд, которые тратятся на TLS handshake. Это короткий, но очень насыщенный обмен сообщениями, без которого ни один HTTPS-запрос не уходит в сеть.
За это время браузер и сервер должны решить три задачи: договориться, на каком языке говорить (версия протокола, набор шифров, алгоритмы подписи), удостовериться, что собеседник действительно тот, за кого себя выдаёт (сертификат), и сгенерировать общий секрет, из которого выводятся ключи шифрования. Всё это нужно сделать так, чтобы пассивный наблюдатель не восстановил ключ, а активный посредник не смог незаметно подменить ответы.
Браузер Сервер
ClientHello ───────►
versions, cipher_suites, key_share,
SNI, ALPN, signature_algorithms
◄─────── ServerHello (выбор)
◄─────── EncryptedExtensions
◄─────── Certificate (внутри TLS!)
◄─────── CertificateVerify
◄─────── Finished
Finished ───────►
GET / ───────► (внутри защищённого канала)
◄─────── 200 OK + payloadЗачем вообще нужен handshake
HTTPS-соединение состоит из двух слоёв. Снаружи — TCP (или QUIC поверх UDP), который доставляет байты. Внутри — защищённый канал, в котором шифруются данные приложения. Чтобы построить этот канал, обеим сторонам нужно сделать четыре вещи одновременно и без права на ошибку: выбрать версию TLS из своих списков (1.2, 1.3, иногда экспериментальные); сошлись по cipher suite (например, TLS_AES_128_GCM_SHA256 для AES-NI или TLS_CHACHA20_POLY1305_SHA256 для мобильных без аппаратного ускорения); согласовать параметры подписи и группы для ECDHE; и наконец договориться о ключе.
Главная инженерная идея TLS 1.3 — ускорение. В TLS 1.2 handshake занимал 2 RTT поверх 1 RTT TCP. На дальних маршрутах (Москва ↔ Калифорния) это легко превращалось в 600–800 мс до первого байта. TLS 1.3 уменьшил handshake до одного RTT, выкинув устаревшие алгоритмы (RSA key exchange, RC4, MD5, SHA-1) и сделав структуру предсказуемой.
ClientHello: визитка клиента
Первое сообщение всегда отправляет клиент. Его содержимое можно мысленно разделить на пять блоков.
- Список версий. В TLS 1.3 поле
legacy_versionпо совместимости равно0x0303(вид TLS 1.2), а реальные версии передаются в расширенииsupported_versions. - Cipher suites. В TLS 1.3 их всего пять, в TLS 1.2 — десятки. Современные браузеры ставят первым
TLS_AES_128_GCM_SHA256на устройствах с AES-NI иTLS_CHACHA20_POLY1305_SHA256там, где AES в железе нет. - Расширения. SNI с именем хоста, ALPN со списком прикладных протоколов (
h2,http/1.1,h3),signature_algorithms,supported_groups(x25519,secp256r1) и главное —key_shareс уже сгенерированной открытой частью ECDHE-ключа. - 32 байта случайности (
client_random). Это число войдёт в формулу вывода ключей и помешает повторному воспроизведению одной и той же сессии. - PSK или session ID. Если соединение возобновляется, сюда кладётся идентификатор предыдущей сессии для быстрого старта.
Именно по этому первому сообщению чаще всего классифицируют клиента: порядок расширений, набор шифров и поддерживаемые группы образуют узнаваемый отпечаток JA3/JA4. Подробнее это разбирается в статье про сигнатуры и метаданные.
Ответ сервера и зашифрованные расширения
Сервер выбирает один cipher suite, одну группу для ECDHE и возвращает ServerHello с собственной случайностью и своим key_share. Уже после этого сообщения обе стороны умеют считать симметричные ключи: каждая перемножает свой приватный ECDHE-ключ с публичным от собеседника и получает один и тот же общий секрет.
Дальше начинается важное отличие от TLS 1.2: все следующие сообщения сервера шифруются handshake-ключом. Открытым текстом летят только ClientHello и ServerHello, дальше идут EncryptedExtensions с параметрами вроде ALPN-результата, потом сертификат сервера, CertificateVerify с подписью по транскрипту и наконец Finished — HMAC по всему handshake. В TLS 1.2 сертификат летел по сети открытым текстом, в 1.3 он закрыт криптографией. SNI же по-прежнему остаётся снаружи — пока не включён ECH, о котором отдельно рассказано в материале про SNI и ECH.
Как браузер проверяет сертификат
Сертификат сервера — это структура X.509, в которой указан домен, открытый ключ, срок действия и подпись вышестоящего удостоверяющего центра. Браузер выполняет несколько проверок последовательно, и любая из них может прервать соединение.
| Проверка | Что именно смотрит браузер |
|---|---|
| Цепочка доверия | От листового сертификата до корневого CA, встроенного в ОС или браузер. Сломанная цепочка — UNKNOWN_ISSUER. |
| Срок действия | Современные сертификаты живут 90–398 дней. С 2026 года Apple и Google идут к 47 дням. |
| Имя | Поле SAN должно содержать запрошенный домен — точно или через wildcard *.example.com для одного уровня. |
| Статус отзыва | OCSP stapling: сервер сам прикладывает свежий ответ от CA. Без него браузер может сходить в OCSP сам или довериться короткому сроку. |
| Прозрачность | SCT-метки от Certificate Transparency-логов. Без них Chrome ругается на любой публичный сайт. |
Если хотя бы одна проверка не сходится, пользователь увидит экран с предупреждением. Это не формальность: без проверки сертификата шифрование защищало бы только от случайного слушателя, но не от активной подмены посередине.
Откуда берётся симметричный ключ и что такое forward secrecy
Полезные данные шифруются быстрыми симметричными алгоритмами вроде AES-GCM или ChaCha20-Poly1305. Но сам AES-ключ нельзя просто отправить по сети — кто угодно мог бы его перехватить. Поэтому используется ECDHE: эллиптический Диффи–Хеллман с эфемерными ключами.
- Стороны договариваются о группе (например,
x25519) и каждая генерирует пару: приватный ключ остаётся у себя, публичный летит вkey_share. - Каждая сторона перемножает свой приватный с чужим публичным и получает общий секрет — но восстановить его, видя только публичные части, вычислительно невозможно.
- Из общего секрета через HKDF выводится дерево ключей: для handshake, для трафика клиент→сервер, для трафика сервер→клиент, для exporter'ов.
Главное свойство ECDHE — forward secrecy. Даже если завтра у сервера украдут приватный ключ сертификата, расшифровать ранее перехваченный трафик не получится: эфемерные ECDHE-ключи каждый раз новые и уже не существуют ни у одной стороны. Именно поэтому в TLS 1.3 RSA key exchange запрещён — он не давал forward secrecy.
1-RTT, 0-RTT и резюмирование сессий
В TLS 1.2 на согласование требовалось 2 RTT поверх трёх RTT TCP. TLS 1.3 спроектирован вокруг 1-RTT: клиент отправляет key_share сразу в первом сообщении, и после ответа сервера может тут же отдавать запрос приложения.
Для повторных подключений есть 0-RTT: клиент берёт PSK от прошлой сессии и сразу шифрует им так называемые early data — например, GET /. Это приятно для скорости, но опасно для повторного воспроизведения: один и тот же запрос может быть доставлен несколько раз, если сетевой посредник его сохранит и переиграет. Поэтому 0-RTT обычно разрешают только для идемпотентных запросов и не разрешают для платежей и POST-форм.
В QUIC и HTTP/3 эти концепции переехали внутрь транспорта, и эффект становится ещё заметнее. Подробнее транспорт разобран в статье про QUIC и TCP.
Типичные ошибки и что они значат на самом деле
| Сообщение | Что произошло |
|---|---|
ERR_SSL_VERSION_OR_CIPHER_MISMATCH | У клиента и сервера нет общей версии или шифра. Часто — устаревший сервер с TLS 1.0 или 1.1. |
NET::ERR_CERT_AUTHORITY_INVALID | Цепочка не доходит до доверенного корня. Самоподписанный сертификат или забытый промежуточный CA. |
NET::ERR_CERT_DATE_INVALID | Сертификат просрочен или часы устройства уехали. Иногда лечится синхронизацией NTP. |
NET::ERR_CERT_COMMON_NAME_INVALID | Домен не совпадает с SAN. Типично при доступе к сайту по IP или поддомену без wildcard. |
handshake_failure | Сервер закрыл соединение посреди обмена. Часто — несовпадение sigalgs или некорректный SNI на multi-tenant хостинге. |
Полезный приём при диагностике — запустить openssl s_client -connect host:443 -servername host -tls1_3 и посмотреть весь handshake глазами. Большинство «загадочных» проблем с HTTPS оказываются ровно в этих сообщениях.
Итого
TLS handshake — не магия и не «формальность перед загрузкой». За 1 RTT в нём решается всё, ради чего вообще существует HTTPS: договорённость о версии, выбор шифров, проверка личности сервера, согласование ключей с forward secrecy и защита транскрипта. Понимание этих шагов делает прозрачными десятки повседневных явлений: от ошибок браузера до поведения CDN, прокси и сетевого оборудования.
Нужен стабильный защищённый доступ к интернету?
TooTimes — зашифрованный туннель до серверов в 9 странах, без логов.
Посмотреть тарифы