// Engineering Log
HTTP, HTTPS и TLS: Часть 4 — Что такое HTTPS и как работает рукопожатие TLS
Опубликовано 02.10.2026
// Быстрый маршрут
Эта статья относится к теме Безопасность и защита.
HTTPS — это HTTP, переданный внутри соединения TLS (Transport Layer Security). TLS решает три задачи: шифрует данные, чтобы их не прочитали по пути; проверяет их целостность, чтобы их не изменили; и подтверждает, что вы говорите именно с сервером example.ru, а не с тем, кто встал посередине. Третья задача решается сертификатом, и без неё первые две бессмысленны: зашифрованный канал к злоумышленнику ничем не защищает.
SSL — старое название протокола. Последняя версия SSL 3.0 запрещена с 2015 года (RFC 7568), но слово прижилось: «SSL-сертификат», ssl_certificate в Nginx, библиотека OpenSSL. Сегодня под SSL всегда подразумевается TLS.
Что шифруется, а что видно
Внутри TLS передаётся весь HTTP: метод, путь, строка запроса, заголовки, cookie, тело. Наблюдатель в сети — провайдер, владелец Wi-Fi, оборудование DPI — видит:
- IP-адреса и порты клиента и сервера;
- имя сайта в поле SNI начального сообщения рукопожатия (если не используется ECH);
- DNS-запрос к этому имени, если DNS не зашифрован;
- объём и время передачи данных;
- параметры рукопожатия, по которым можно определить тип клиента (подробнее — «Что такое JA3 и JA4»).
Путь /account/orders?id=42 и содержимое страницы не видны. Поэтому блокировки в сети работают по IP-адресу, по SNI или по DNS, но не по отдельным страницам.
Сертификат
Сертификат X.509 — это открытый ключ сервера вместе с данными о том, кому он принадлежит, подписанный удостоверяющим центром (CA). Главные поля:
- Subject Alternative Name (SAN) — список имён, для которых действует сертификат:
example.ru,www.example.ru,*.example.ru. Браузеры проверяют только SAN, поле Common Name для проверки имени не используется с 2017 года; - срок действия —
notBeforeиnotAfter; - издатель — кто подписал;
- открытый ключ — RSA (обычно 2048 бит) или ECDSA (P-256).
Звёздочка в SAN покрывает один уровень: *.example.ru подходит для shop.example.ru, но не для example.ru и не для a.shop.example.ru.
Сроки жизни сокращаются. Индустриальный консорциум CA/Browser Forum в 2025 году принял поэтапное сокращение максимального срока публичных сертификатов: 200 дней с 15 марта 2026 года, 100 дней с марта 2027-го и 47 дней с марта 2029-го. Сертификаты Let’s Encrypt живут 90 дней, и проект переходит на ещё более короткие сроки. Итог один: выпуск и продление должны быть автоматическими (ACME-клиент certbot, acme.sh, встроенный ACME в Caddy и Traefik).
Цепочка доверия
Сертификат сайта подписан не корневым сертификатом CA, а промежуточным. Цепочка выглядит так:
example.ru ← сертификат сайта (leaf), подписан промежуточным
└ R11 (Let's Encrypt) ← промежуточный, подписан корневым
└ ISRG Root X1 ← корневой, лежит в хранилище доверенных у ОС или браузераСервер обязан отправить сертификат сайта и все промежуточные. Корневой отправлять не нужно — он уже есть у клиента. Самая частая ошибка настройки — сервер отдаёт только сертификат сайта без промежуточного. Браузеры на компьютере часто это прощают (Chrome и Firefox умеют находить или кешировать промежуточные сертификаты), а curl, Python, Java и мобильные приложения — нет, и выдают ошибку проверки. У certbot поэтому в Nginx указывают fullchain.pem, а не cert.pem.
Клиент проверяет:
- каждая подпись в цепочке верна, а цепочка заканчивается корнем из доверенного хранилища;
- сертификаты не просрочены;
- имя сайта есть в SAN;
- сертификат не отозван (механизмы отзыва устроены по-разному у разных браузеров; Let’s Encrypt в 2025 году прекратил поддержку OCSP и публикует только списки отзыва CRL).
Рукопожатие TLS 1.3
TLS 1.3 (RFC 8446, 2018) устанавливает защищённое соединение за один круг обмена сообщениями (1-RTT) поверх уже открытого TCP-соединения.
1. ClientHello (клиент → сервер, открытым текстом):
- поддерживаемые версии (расширение
supported_versions); - список шифронаборов:
TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256; - поддерживаемые группы для обмена ключами:
X25519MLKEM768,x25519,secp256r1; - key_share — сразу готовая открытая часть ключа для одной или двух групп. Клиент угадывает, какую выберет сервер, и благодаря этому экономит круг обмена;
- SNI — имя сайта, чтобы сервер выбрал нужный сертификат;
- ALPN — какие протоколы клиент готов использовать поверх TLS:
h2,http/1.1; - случайное число и другие расширения.
2. ServerHello (сервер → клиент): выбранный шифронабор и своя часть ключа. С этого момента у обеих сторон есть общий секрет (алгоритм обмена ключами Диффи — Хеллмана), и всё дальнейшее шифруется.
3. Зашифрованная часть от сервера:
EncryptedExtensions— выбранный протокол ALPN и прочие параметры;Certificate— цепочка сертификатов;CertificateVerify— подпись всей переписки закрытым ключом сертификата. Так сервер доказывает, что владеет ключом, а не просто переслал чужой сертификат;Finished— контрольная сумма рукопожатия.
4. Finished от клиента — и сразу первый HTTP-запрос в том же пакете.
В TLS 1.3 даже сертификат сервера передаётся зашифрованным, и пассивный наблюдатель не видит, какой сертификат вернул сервер. Открытыми остаются ClientHello и ServerHello.
Если клиент угадал не ту группу в key_share, сервер отвечает HelloRetryRequest, и рукопожатие занимает два круга.
Возобновление сессии и 0-RTT. После рукопожатия сервер выдаёт клиенту билет (session ticket). При следующем подключении клиент предъявляет его и пропускает проверку сертификата, а в режиме 0-RTT отправляет первый запрос прямо вместе с ClientHello. Данные 0-RTT можно перехватить и отправить повторно, поэтому их используют только для безопасных запросов вроде GET; в Nginx 0-RTT выключен по умолчанию (ssl_early_data off).
Рукопожатие TLS 1.2
TLS 1.2 (RFC 5246, 2008) ещё широко поддерживается и требует двух кругов обмена:
- ClientHello — версии и шифронаборы;
- ServerHello, Certificate (открытым текстом), ServerKeyExchange, ServerHelloDone;
- ClientKeyExchange, ChangeCipherSpec, Finished от клиента;
- ChangeCipherSpec и Finished от сервера — только теперь можно отправлять HTTP.
Отличия от 1.3, важные на практике:
- на один круг медленнее: при задержке 100 мс до сервера это 100 мс к каждому новому соединению;
- сертификат сервера виден в сети;
- допускает устаревшие алгоритмы: обмен ключами RSA без прямой секретности, шифры CBC, SHA-1. Их нужно отключать в настройках сервера (подробнее — «Версии TLS, шифронаборы, SNI, ALPN, ECH и mTLS»);
- при обмене ключами RSA тот, кто позже получит закрытый ключ сервера, расшифрует все записанные ранее сессии. В TLS 1.3 такой обмен убран: ключи сессий эфемерные, и утечка ключа сертификата не раскрывает прошлый трафик. Это свойство называется прямой секретностью (forward secrecy).
Где заканчивается TLS
TLS защищает участок между клиентом и тем, кто держит сертификат. Если перед сайтом стоит CDN или обратный прокси, TLS от браузера заканчивается на нём (TLS termination), а дальше, до вашего сервера, запрос идёт отдельным соединением. Этот второй участок тоже нужно шифровать, если он проходит через чужую сеть: у Cloudflare, например, режим Flexible отправляет запросы на сервер по обычному HTTP, и между CDN и сервером данные идут открыто. Нужен режим Full (strict) с проверкой сертификата на сервере.
Посмотрите рукопожатие сами
Шаги рукопожатия. Ключ -state у openssl s_client печатает каждое сообщение, которое клиент отправил или получил. Вывод для TLS 1.3 (сайт за CloudFront, сентябрь 2026 года):
echo | openssl s_client -connect example.ru:443 -servername example.ru -state 2>&1 | grep -E '^SSL_connect|^Negotiated|^New'SSL_connect:SSLv3/TLS write client hello
SSL_connect:SSLv3/TLS read server hello
SSL_connect:TLSv1.3 read encrypted extensions
SSL_connect:SSLv3/TLS read server certificate
SSL_connect:TLSv1.3 read server certificate verify
SSL_connect:SSLv3/TLS read finished
SSL_connect:SSLv3/TLS write change cipher spec
SSL_connect:SSLv3/TLS write finished
Negotiated TLS1.3 group: X25519MLKEM768
New, TLSv1.3, Cipher is TLS_AES_128_GCM_SHA256Всё, что ниже read server hello, клиент получил уже зашифрованным. change cipher spec в TLS 1.3 — пустое сообщение для совместимости со старым сетевым оборудованием. Группа X25519MLKEM768 — гибридный постквантовый обмен ключами (подробнее — в статье «Версии TLS, шифронаборы, SNI, ALPN, ECH и mTLS»).
Тот же сервер с ключом -tls1_2:
SSL_connect:SSLv3/TLS write client hello
SSL_connect:SSLv3/TLS read server hello
SSL_connect:SSLv3/TLS read server certificate
SSL_connect:SSLv3/TLS read server key exchange
SSL_connect:SSLv3/TLS read server done
SSL_connect:SSLv3/TLS write client key exchange
SSL_connect:SSLv3/TLS write change cipher spec
SSL_connect:SSLv3/TLS write finished
SSL_connect:SSLv3/TLS read server session ticket
SSL_connect:SSLv3/TLS read change cipher spec
SSL_connect:SSLv3/TLS read finishedЗдесь видны оба круга обмена: сертификат и ключ сервера приходят открытым текстом, клиент отвечает своим ключом и ждёт finished от сервера. Полный разбор сообщений — ключ -msg, а в сборках OpenSSL с поддержкой трассировки — -trace.
Сколько стоит лишний круг. Замер curl’ом одного и того же сайта, по пять запросов на каждую версию, среднее:
curl --tlsv1.2 --tls-max 1.2 -s -o /dev/null -w '%{time_connect} %{time_appconnect}\n' https://example.ru/
curl --tlsv1.3 -s -o /dev/null -w '%{time_connect} %{time_appconnect}\n' https://example.ru/| Версия | TCP (≈ 1 RTT) | Рукопожатие TLS |
|---|---|---|
| TLS 1.2 | 15 мс | 37 мс |
| TLS 1.3 | 17 мс | 23 мс |
Рукопожатие TLS 1.2 заняло примерно два RTT, TLS 1.3 — чуть больше одного (плюс время на вычисления). На сервере в другом полушарии, где RTT 150–200 мс, разница между версиями — уже 150–200 мс на каждое новое соединение.
В Wireshark. Фильтр tls.handshake оставит только сообщения рукопожатия. В TLS 1.2 у пакета Certificate можно раскрыть сертификат сервера; в TLS 1.3 после ServerHello видны только записи Application Data — сертификат зашифрован.
В браузере. Щелчок по значку слева от адреса → «Безопасное подключение» → «Сертификат действителен» покажет цепочку, а в Chrome на вкладке Security в DevTools — версию TLS, группу обмена ключами и шифр.
Самоподписанные и корпоративные сертификаты
Самоподписанный сертификат шифрует так же надёжно, но клиенту нечем проверить, что он настоящий, и браузер показывает предупреждение. Для внутренних сервисов вместо самоподписанных сертификатов лучше завести собственный внутренний CA (например, step-ca) и установить его корневой сертификат на рабочие места.
Корпоративные системы защиты и антивирусы часто расшифровывают HTTPS: устанавливают на компьютер свой корневой сертификат и выпускают на лету поддельные сертификаты для каждого сайта. В браузере это видно по издателю сертификата — вместо Let’s Encrypt или другого публичного CA там имя антивируса или компании. Приложения со встроенным списком доверенных сертификатов (pinning) в такой сети перестают работать.
Типичные ошибки
- В Nginx указан
cert.pemвместоfullchain.pem— браузер работает, а API из Python и мобильного приложения падает с ошибкой проверки сертификата. - Сертификат выпущен на
example.ru, а пользователи заходят наwww.example.ru— ошибка несовпадения имени. - Продление настроено, но веб-сервер после него не перезагружает сертификат — сайт отдаёт старый, уже просроченный.
- Шифрование только до CDN, а от CDN до сервера — открытый HTTP.
- Для проверки «работает ли» используется
curl -kв скриптах мониторинга — проверка сертификата отключена, и истечение срока никто не замечает.
// Похожая задача
Если у вас похожая ситуация
Эта статья относится к одной из рабочих тем. Можно продолжить чтение по теме, перейти на главную, чтобы понять, чем я занимаюсь, или сразу открыть услуги.
Тема статьи
Безопасность и защита
SSL, hardening, доступы, защита сервисов и безопасные конфигурации.
Часто с этим приходят
- Настроить SSL, сертификаты и безопасные подключения
- Ограничить доступы и закрыть лишние точки входа
- Усилить конфигурацию сервера и сервисов
// Следующий шаг
Если вам нужна не только статья, а помощь по этой теме, удобнее сразу перейти в услугу. Главная и подборка материалов остаются рядом.
Открыть услуги// Contact
Нужна помощь?
Свяжись со мной и я помогу решить проблему
Написать в TelegramОтвечаю в течение рабочего дня (03:00–13:00 GMT)
Или оставьте заявку здесь:
// Related