Как на самом деле работают HTTPS и TLS: разбор рукопожатия
Вы установили сертификат, браузер показывает замок, и вы двигаетесь дальше. Но в один прекрасный день API-клиент падает с ошибкой SSL_ERROR_RX_RECORD_TOO_LONG, мобильное приложение отклоняет вашу цепочку, или после включения HSTS появляется бесконечный редирект. Внезапно HTTPS превращается в чёрный ящик.
Эта статья открывает этот ящик. Мы разберём, что на самом деле происходит во время TLS-рукопожатия, зачем нужны сертификаты, где применяется симметричное, а где асимметричное шифрование, и как отлаживать сбои, с которыми вы реально столкнётесь в продакшене.
Что такое HTTPS на самом деле
HTTPS — это не отдельный протокол. Это обычный HTTP, передаваемый по TLS-зашифрованному соединению. Меняется схема URL, порт по умолчанию смещается с 80 на 443, а всё остальное — методы, заголовки, коды состояния, куки — ведёт себя точно так же.
TLS даёт три гарантии поверх TCP:
- Конфиденциальность — посредники не могут прочитать трафик.
- Целостность — подмена данных в пути обнаруживается.
- Аутентификация — клиент может убедиться, что общается с сервером, владеющим доменом.
Именно третью гарантию часто недооценивают. Шифрование без аутентификации бесполезно: злоумышленник, перехвативший трафик, мог бы просто предъявить свой собственный ключ.
Рукопожатие TLS 1.3 шаг за шагом
TLS 1.3 значительно упростил рукопожатие по сравнению с TLS 1.2. Вот как проходит обмен между браузером и сервером:
- ClientHello — клиент отправляет поддерживаемые версии TLS, наборы шифров, случайное значение и долю ключа для группы Diffie-Hellman (например, X25519).
- ServerHello — сервер выбирает набор шифров и отправляет свою долю ключа. Теперь обе стороны могут вычислить общий секрет.
- Зашифрованные расширения и сертификат — сервер отправляет свою цепочку сертификатов, уже зашифрованную производными ключами.
- Finished — обе стороны отправляют MAC по стенограмме рукопожатия, доказывая, что ничего не было подменено.
- Данные приложения — HTTP-запросы и ответы идут по установленной сессии.
В TLS 1.3 полное рукопожатие стоит одного кругового обхода, а возобновление может достигать нуля круговых обходов. TLS 1.2 требовал двух круговых обходов, прежде чем могли пойти данные приложения.
Почему сертификат отправляется после выработки ключей
В TLS 1.3 сертификат зашифрован. Это значит, что пассивный наблюдатель не может даже увидеть по сертификату, какой домен посещает клиент, что снижает утечку информации. Это также означает, что инструменты отладки, ожидающие увидеть сертификат в открытом виде в первых пакетах, будут в замешательстве.
Симметричное и асимметричное шифрование
Распространённое заблуждение — что HTTPS шифрует всё публичным ключом сервера. Это не так. Асимметричная криптография медленная и ограничена по размеру; она используется только для установления общего секрета.
| Этап | Криптография | Назначение |
|---|---|---|
| Обмен ключами | Асимметричная (ECDHE) | Согласовать общий секрет, не передавая его |
| Аутентификация | Асимметричные подписи | Доказать, что сервер владеет ключом сертификата |
| Основные данные | Симметричная (AES-GCM или ChaCha20-Poly1305) | Быстрое шифрование и целостность для HTTP-трафика |
Обмен ключами Диффи-Хеллмана обладает ценным свойством — прямой секретностью (forward secrecy): даже если приватный ключ сервера утечёт позже, записанные прошлые сессии нельзя расшифровать, потому что ключи сессии никогда не выводились из этого долгосрочного ключа.
Что внутри сертификата
Сертификат X.509 связывает публичный ключ с доменным именем. Он содержит:
- Субъект (домен) и альтернативные имена субъекта (SAN), которые браузеры фактически проверяют.
- Публичный ключ и его алгоритм.
- Срок действия.
- Издателя и подпись этого издателя.
Браузеры доверяют фиксированному набору корневых удостоверяющих центров. Ваш сервер отправляет промежуточный сертификат, и браузер строит цепочку от вашего конечного сертификата до доверенного корня. Если промежуточный сертификат отсутствует, десктопные браузеры могут всё ещё работать, потому что кэшируют промежуточные сертификаты, а мобильные клиенты и инструменты командной строки падают. Это самая распространённая ошибка TLS в продакшене.
Практические шаги отладки
Когда HTTPS ведёт себя неправильно, двигайтесь снаружи внутрь.
- Проверьте цепочку командой
openssl s_client -connect example.com:443 -servername example.com -showcerts. Убедитесь, что сервер отправляет полную цепочку, а не только конечный сертификат. - Проверьте срок действия — просроченные сертификаты дают жёсткий отказ без возможности обхода.
- Проверьте имя хоста — список SAN должен содержать точное имя хоста, которое запрашивает клиент, включая префикс
www, если он есть. - Проверьте версию протокола — если устаревший клиент поддерживает только TLS 1.0, а ваш сервер требует TLS 1.2+, рукопожатие падает ещё до HTTP.
- Проверьте редиректы — редирект с HTTPS на HTTP и обратно создаёт петлю; исправляйте это в конфигурации сервера, а не в коде приложения.
# Inspect the certificate chain and negotiated protocol
openssl s_client -connect example.com:443 \
-servername example.com -showcerts < /dev/null 2>&1 | \
openssl x509 -noout -subject -issuer -dates
# Test a specific TLS version
openssl s_client -connect example.com:443 -tls1_2 < /dev/nullВ Nginx директива ssl_certificate должна указывать на файл, содержащий конечный сертификат, за которым следует промежуточный, именно в таком порядке. Объединение их в неправильном порядке приводит к ошибкам цепочки, которые легко пропустить.
HSTS и цена ошибки
HTTP Strict Transport Security сообщает браузерам использовать HTTPS для домена в течение заданного периода. Это мощно и беспощадно: как только браузер увидел длительный max-age, он будет отказываться от простого HTTP, даже если вы позже отключите HTTPS на сервере.
Начните с короткого max-age, убедитесь, что всё работает, затем увеличивайте его. Добавляйте includeSubDomains только после того, как каждый поддомен обслуживает валидный HTTPS. Предзагрузка (preloading) фактически необратима — запрашивайте её только когда вы уверены.
Распространённые ошибки конфигурации
- Смешанный контент — HTTPS-страница загружает скрипты или изображения по HTTP. Браузеры блокируют активный смешанный контент и предупреждают о пассивном.
- Слабые наборы шифров — оставленные включёнными шифры в режиме CBC и старые версии протокола ради совместимости, которая вам больше не нужна.
- Отсутствие обработки OCSP или CRL — проверка отзыва на практике ненадёжна; короткоживущие сертификаты — более надёжное решение.
- Пробелы в автоматизации сертификатов — обновление работает, но шаг перезагрузки, который заставляет сервер подхватить новый сертификат, отсутствует.
Относитесь к обновлению сертификатов как к конвейеру развёртывания, а не как к напоминанию в календаре. Если обновление требует участия человека, оно рано или поздно подведёт в самый неподходящий момент.
FAQ
Шифрует ли HTTPS доменное имя, которое я посещаю?
Домен появляется в расширении TLS SNI и обычно виден в сети. Путь и строка запроса зашифрованы, но сетевой наблюдатель, как правило, может видеть, к какому хосту вы подключились.
Почему мой сайт работает в браузере, но падает в curl или мобильном приложении?
Почти всегда это отсутствующий промежуточный сертификат. Браузеры часто кэшируют промежуточные сертификаты с предыдущих посещений, а curl и многие мобильные HTTP-стеки требуют, чтобы сервер отправлял полную цепочку.
TLS 1.3 всегда лучше TLS 1.2?
Для современных клиентов — да: меньше круговых обходов, меньший набор шифров и прямая секретность по умолчанию. Оставляйте TLS 1.2 включённым только если вы всё ещё обслуживаете клиентов, которые не могут договориться о 1.3.
Когда вам нужно просмотреть логи серверов, терминирующих TLS, быстрый проход через анализатор логов Nginx помогает выявить сбои рукопожатия, петли редиректов и необычное поведение клиентов до того, как они превратятся в сбои.