// 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.

Клиент проверяет:

  1. каждая подпись в цепочке верна, а цепочка заканчивается корнем из доверенного хранилища;
  2. сертификаты не просрочены;
  3. имя сайта есть в SAN;
  4. сертификат не отозван (механизмы отзыва устроены по-разному у разных браузеров; 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) ещё широко поддерживается и требует двух кругов обмена:

  1. ClientHello — версии и шифронаборы;
  2. ServerHello, Certificate (открытым текстом), ServerKeyExchange, ServerHelloDone;
  3. ClientKeyExchange, ChangeCipherSpec, Finished от клиента;
  4. 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 года):

bash
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’ом одного и того же сайта, по пять запросов на каждую версию, среднее:

bash
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.215 мс37 мс
TLS 1.317 мс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)

Или оставьте заявку здесь:

Подтвердите, что вы не бот.

Написать и получить быстрый ответ