Перейти к содержимому
New

DeepSeek V4.1 Flash free for 7 days: 10M tokens a day after a top-up of $10 or more. Until Nov 30.

How it works

Что такое TLS и как HTTPS защищает трафик

TLS 1.3 даёт HTTPS конфиденциальность, целостность и аутентификацию сервера. Разбираем рукопожатие, цепочки сертификатов и то, чего замок в адресной строке не доказывает.

Начальный10 мин чтенияАвтор: NotHoly

Коротко

TLS (Transport Layer Security) — протокол, который оборачивает сетевое соединение в шифрование. HTTPS — обычный HTTP, идущий через соединение TLS. Когда браузер показывает замок, он уже сделал три вещи. Зашифровал данные. Проверил, что по пути их никто не изменил. И убедился, что сервер доказал владение сертификатом, которому доверяют для введённого вами имени.

Третий пункт понимают неправильно чаще всего. HTTPS говорит, с каким сервером вы общаетесь. О том, можно ли этому серверу доверять, честен ли он и хорошо ли им управляют, HTTPS не говорит ничего.

Почему простого HTTP мало

В статье Как работает HTTP запросы и ответы — это текстовые сообщения, и HTTP ничего не делает, чтобы их скрыть. Их может прочитать любое устройство между вами и сервером: домашний роутер, точка доступа в кафе, ваш интернет-провайдер и сети на пути.

Пассивный наблюдатель может прочитать форму входа, отправленную по простому HTTP. Активный атакующий на пути способен на большее: изменить страницу до того, как она дойдёт до вас, вставить скрипт или подменить загрузку изменённым файлом. TLS создан, чтобы остановить обе угрозы. Кроме того, он даёт клиенту способ проверить, кто отвечает, чего простой HTTP не умеет вообще.

Что даёт TLS 1.3

Текущая версия — TLS 1.3, определённая в RFC 8446. TLS 1.0 и 1.1 объявлены устаревшими, как объясняет RFC 8996, а TLS 1.2 всё ещё широко распространён. В версии 1.3 убрали многие старые опции, поэтому способов плохо настроить рукопожатие стало меньше.

TLS 1.3 даёт три свойства.

Конфиденциальность

Данные приложения шифруются сеансовыми ключами, которые есть только у двух эндпоинтов. Наблюдатель видит шифртекст. Размер и тайминг трафика остаются видны, а содержимое скрыто.

Полное рукопожатие TLS 1.3 использует эфемерный обмен ключами. Обе стороны создают временные значения ключей на сеанс и затем их уничтожают. Это даёт forward secrecy (прямую секретность): если приватный ключ сертификата сервера утечёт спустя годы, записанные старые сеансы всё равно должны остаться нечитаемыми. Утёкший ключ всё же позволяет атакующему выдавать себя за сервер начиная с этого момента, так что forward secrecy защищает прошлое и не защищает будущее.

Целостность

Каждая запись несёт тег аутентификации от шифра AEAD, например AES-GCM или ChaCha20-Poly1305. TLS 1.3 разрешает только такие шифры. Если атакующий изменит бит при передаче, проверка тега не пройдёт и запись будет отклонена.

Аутентификация сервера

Сервер доказывает, что владеет приватным ключом, соответствующим его сертификату. Сертификат привязывает этот публичный ключ к имени вроде example.com. Клиент проверяет сертификат и стоящую за ним цепочку доверия, затем проверяет имя. Этому посвящена большая часть оставшейся статьи.

Рукопожатие по шагам

Рукопожатие согласует ключи и доказывает подлинность до того, как пойдут данные HTTP. В TLS 1.3 обычное рукопожатие занимает один круговой обмен (round trip). Шаги ниже в общих чертах следуют RFC 8446.

Шаг 1: ClientHello

Клиент отправляет ClientHello. В нём перечислены поддерживаемые версии TLS и наборы шифров, а также key share, временное публичное значение клиента для обмена ключами. Ещё в нём открытым текстом идёт server name indication (SNI), имя хоста, которое вы запросили. Серверам, на которых размещено много сайтов, это имя нужно для выбора правильного сертификата.

Шаг 2: ServerHello

Сервер выбирает версию и набор шифров и отправляет свой key share. Каждая сторона объединяет своё приватное значение с публичным значением другой стороны и получает один и тот же общий секрет. Наблюдатель, видевший оба публичных значения, вычислить этот секрет не может. С этого момента рукопожатие зашифровано.

Шаг 3: сертификат и доказательство

Сервер отправляет свой сертификат. В TLS 1.2 сертификат был виден в трафике. В TLS 1.3 он идёт внутри зашифрованной части рукопожатия.

Затем сервер отправляет сообщение CertificateVerify, подпись транскрипта рукопожатия, сделанную приватным ключом сертификата. Так сервер доказывает, что ключ есть у него во время этого рукопожатия. Скопированный сертификат сам по себе атакующему бесполезен. Сообщение Finished, MAC от транскрипта, завершает часть сервера.

Шаг 4: клиент проверяет и завершает

Клиент проверяет цепочку сертификатов, сроки действия, соответствие имени в сертификате запрошенному хосту и подпись CertificateVerify. Если все проверки проходят, клиент отправляет своё сообщение Finished, и данные приложения могут идти.

Если проверка не проходит, клиент останавливается. Браузер показывает предупреждение о сертификате, а curl завершается с ошибкой. Для новичка эти сообщения — самая полезная часть TLS, потому что они называют непройденную проверку.

Сертификаты и цепочки доверия

Сертификат — это структура X.509, а профиль, используемый в интернете, определён в RFC 5280. Здесь важнее всего такие поля.

Поле Что оно говорит
Subject Сущность, которую называет сертификат. У веб-сертификатов часто повторяет имя хоста.
Subject Alternative Name (SAN) Имена, которые покрывает сертификат, например example.com или *.example.com. Клиенты сравнивают запрошенный хост с этим списком.
Issuer Удостоверяющий центр (CA), подписавший этот сертификат.
Validity Даты notBefore и notAfter. Вне этого окна сертификат недействителен.
Basic Constraints Может ли этот сертификат подписывать другие сертификаты. Так помечены сертификаты CA.

Современные клиенты игнорируют Common Name (CN) в subject при проверке имени хоста и используют список SAN. Читатель, который смотрит только на CN, может неверно оценить сертификат.

Как проверяется цепочка

Сервер редко предъявляет сертификат, который клиент может проверить напрямую. Обычно конечный сертификат (leaf), покрывающий имя хоста, подписан промежуточным CA, а тот подписан корневым CA. Клиент доверяет набору корневых сертификатов, поставляемых с операционной системой или браузером.

Клиент строит путь от конечного сертификата до доверенного корня. На каждом звене он проверяет подпись и сроки действия и подтверждает, что издатель вправе подписывать сертификаты. Затем проверяет имя хоста. Пройти должны обе проверки.

Любой доверенный корень в принципе может выпустить сертификат для любого имени. Поэтому доверие зависит от практик центров в хранилище. Именно по этой причине вендоры удаляют центры, ошибочно выпускающие сертификаты.

Отзыв

Сертификат можно отозвать до истечения срока, например после компрометации ключа. Клиенты могут проверять отзыв через списки отзыва сертификатов (CRL) или OCSP, но работают эти проверки по-разному. Соединение без ошибок не доказывает, что сертификат никогда не отзывали.

Что TLS не защищает

Сервер

TLS подтверждает личность сервера. Его поведение он не оценивает. Фишинговый сайт может получить действительный сертификат для похожего домена, который он контролирует. Замок тогда показывает, что соединение дошло до владельца ключа этого домена. Что домен принадлежит вашему банку, он не показывает. Прочитайте имя хоста в адресной строке, прежде чем доверять странице. Сервер с правильным сертификатом всё равно могут взломать, или им могут плохо управлять.

Метаданные

TLS скрывает содержимое, но не все факты о соединении. Любой на пути по-прежнему видит IP-адреса обеих сторон, порт, примерный размер и тайминг трафика, а также имя сервера в ClientHello, потому что SNI передаётся открытым текстом. Encrypted Client Hello — это работа IETF по сокрытию SNI, но проверьте, насколько широко она внедрена, прежде чем считать, что сайт её использует. DNS-запросы идут по отдельному протоколу и раскрывают имена, которые вы запрашиваете, если вы не используете зашифрованный DNS.

Эндпоинты

TLS защищает данные, пока они идут между двумя эндпоинтами. Сами эндпоинты он не защищает. Вредоносное ПО на вашем компьютере может прочитать расшифрованные данные, а расширение браузера может читать каждую открываемую страницу. Компания также может установить на вашу машину собственный доверенный корень и расшифровывать HTTPS-трафик через инспектирующий прокси. Клиент при этом работает точно так, как настроен, а решение о доверии принимает тот, кто контролирует хранилище корней.

Лабораторная: смотрим HTTPS к example.com

example.com — одно из имён, которые IANA резервирует для документации и примеров. Все команды ниже подключаются только к example.com. Лабораторная ничего не меняет на сервере и не требует аккаунта. Нужен терминал с curl и openssl. Команды openssl выполнялись с OpenSSL 3.2.4.

Ваш вывод будет отличаться от показанного здесь. IP-адреса меняются, сертификаты перевыпускаются, даты сдвигаются вперёд.

Шаг 1: посмотрите обмен через curl

bash
curl -vI https://example.com

Флаг -v печатает подробности соединения, а -I отправляет запрос HEAD, который запрашивает только заголовки. На машине, где готовилась статья (Windows 11 с Git Bash, curl 8.12.1, запуск 8 ноября 2026 года), нужные строки выглядели так:

text
* Host example.com:443 was resolved.
* IPv4: 172.66.147.243, 104.20.23.154
* Connected to example.com (172.66.147.243) port 443
* using HTTP/1.x
> HEAD / HTTP/1.1
> Host: example.com
< HTTP/1.1 200 OK

Эта сборка curl использует Schannel, библиотеку TLS в Windows, и её подробный вывод отличается от curl, собранного с OpenSSL. Здесь curl не напечатал строки с версией TLS, шифром и сертификатом, которые нужны для этой лабораторной. В curl на OpenSSL ищите строку с версией TLS и шифром и блок сертификата с subject, issuer и датой истечения. Следующие шаги получают те же факты через openssl.

200 OK означает, что сервер ответил внутри соединения TLS. Заголовки идут зашифрованными, и curl расшифровывает их локально.

Шаг 2: получите краткую сводку через openssl

bash
openssl s_client -connect example.com:443 -servername example.com -brief </dev/null

Вывод:

text
Connecting to 172.66.147.243
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Peer certificate: CN=example.com
Hash used: SHA256
Signature type: ECDSA
Verification: OK
Server Temp Key: X25519, 253 bits
DONE

Читаем построчно:

  • Protocol version: версия TLS, согласованная для этого соединения.
  • Ciphersuite: записи защищает AES-256-GCM, а в расписании ключей используется SHA-384.
  • Signature type: ECDSA, алгоритм ключа сертификата.
  • Verification: OK, то есть цепочка прошла проверку по хранилищу доверия этой сборки openssl.
  • Server Temp Key: X25519, эфемерный обмен ключами, дающий forward secrecy.

Флаг -servername задаёт SNI. Без него сервер с несколькими сайтами может вернуть сертификат по умолчанию, не совпадающий с нужным именем. Перенаправление </dev/null закрывает стандартный ввод, чтобы команда завершилась.

Шаг 3: прочитайте поля сертификата

bash
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates

Вывод:

text
subject=CN=example.com
issuer=C=US, O=SSL Corporation, CN=Cloudflare TLS Issuing ECC CA 3
notBefore=Sep 26 22:49:11 2026 GMT
notAfter=Dec 25 22:56:35 2026 GMT

В subject только CN. Issuer — промежуточный CA, не корневой. Окно действия было открыто в день лабораторной и закрывается 25 декабря 2026 года. Сравните notAfter с датой в своей системе, потому что просроченный сертификат не проходит проверку, даже когда его цепочка в порядке.

В subject не перечислены покрываемые имена, поэтому запросите список SAN:

bash
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -ext subjectAltName

Вывод:

text
X509v3 Subject Alternative Name:
    DNS:example.com, DNS:*.example.com

Wildcard покрывает имена вроде www.example.com. Клиент сравнивает этот список с хостом в вашем URL.

Шаг 4: выведите цепочку, присланную сервером

bash
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null | grep -E '^ *[0-9] s:|^ *i:'

Вывод:

text
 0 s:CN=example.com
   i:C=US, O=SSL Corporation, CN=Cloudflare TLS Issuing ECC CA 3
 1 s:C=US, O=SSL Corporation, CN=Cloudflare TLS Issuing ECC CA 3
   i:C=US, O=SSL Corporation, CN=SSL.com TLS Transit ECC CA R2
 2 s:C=US, O=SSL Corporation, CN=SSL.com TLS Transit ECC CA R2
   i:C=US, O=SSL Corporation, CN=SSL.com TLS ECC Root CA 2022
 3 s:C=US, O=SSL Corporation, CN=SSL.com TLS ECC Root CA 2022
   i:C=GB, ST=Greater Manchester, L=Salford, O=Comodo CA Limited, CN=AAA Certificate Services

Каждая строка s: — subject, а каждая строка i: — его issuer. Запись 0 — конечный сертификат, и каждую запись выпускает следующая за ней. Сертификаты могут быть кросс-подписаны, поэтому цепочка может дойти до корня несколькими путями. Клиенту нужен один действительный путь, заканчивающийся корнем в его хранилище.

Шаг 5: убедитесь, что цепочка проходит проверку

bash
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | grep 'Verify return code'

Вывод:

text
Verify return code: 0 (ok)

Ноль означает, что хранилище доверия этой сборки openssl приняло цепочку. Другие значения называют конкретный сбой, например просроченный сертификат.

Шаг 6: намеренно провалите проверку имени

bash
openssl s_client -connect example.com:443 -servername example.com -verify_hostname example.org -brief </dev/null

Вывод с сокращениями:

text
depth=0 CN=example.com
verify error:num=62:hostname mismatch
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Peer certificate: CN=example.com
Verification error: hostname mismatch

Команда по-прежнему подключается только к example.com. Флаг -verify_hostname просит openssl проверить сертификат на соответствие example.org, который сертификат не покрывает. Браузер покажет такой же сбой. Именно эта проверка не даёт серверу с действительным сертификатом для одного домена выдать себя за другой.

Что вынести из лабораторной

Соединение согласовало TLS 1.3, а клиент принял цепочку для example.com и отверг тот же сертификат для example.org. Ни один из этих результатов не говорит, можно ли доверять компании, стоящей за example.com. Лабораторная показывает только то, что клиент добрался до владельца ключа для example.com.

Частые ошибки

  • Считать замок оценкой доверия. Он означает, что канал зашифрован и сертификат прошёл проверку. Сайт он не оценивает.
  • Проверять только CN. Современные клиенты сравнивают имя хоста со списком SAN.
  • Прокликивать предупреждение о сертификате. Предупреждение значит, что проверка не прошла. Выясните, какая именно, прежде чем продолжать.
  • Добавлять -k или --insecure в curl, чтобы ошибка исчезла. Это отключает проверки, о которых вы только что прочитали. Используйте флаг только с одноразовым тестовым сервером и никогда с настоящими учётными данными.
  • Писать код с отключённой проверкой, например verify=False в HTTP-клиенте на Python. Данные по-прежнему шифруются, только получит их тот, кто ответил.

Что дальше

Прочитайте разделы обзора и рукопожатия в RFC 8446, затем просмотрите RFC 5280 ради полей сертификата. Прочитайте руководство Mozilla Server Side TLS и запустите проверку конфигурации на сервере, которым вы управляете.

Следующая статья этой серии посвящена публичным и приватным ключам, математике, стоящей за сертификатом. Если шаг с поиском имени вам внове, сначала прочитайте Что такое DNS?, потому что от его результата зависит, к какому адресу пойдёт рукопожатие.

Источники

Источники

  1. RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3
  2. RFC 5280: Internet X.509 Public Key Infrastructure Certificate and CRL Profile
  3. Mozilla: Security/Server Side TLS
  4. OpenSSL documentation: openssl-s_client
  5. RFC 8996: Deprecating TLS 1.0 and TLS 1.1
  6. IANA: Example domains

Ещё по теме: Сети и веб

Сети и веб

TCP/IP и порты: как сервисы слушают на вашей машине

Порт — это пронумерованная дверь на вашей машине. Разбираем, как TCP и UDP работают с портами, затем запускаем, находим и проверяем локальный сервер на 127.0.0.1.

Начальный10 мин чтения