RE:NODE

Как работает HTTPS: простыми словами

Автор Команда RE:NODE
15 мин чтения


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

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

HTTP и HTTPS: что на самом деле меняется#

Обычный HTTP - это текст, который передаётся открыто. Запрос страницы входа в сети выглядит точно так же, как его написал браузер:

code
POST /login HTTP/1.1Host: shop.example.comContent-Type: application/x-www-form-urlencodedemail=anna%40example.com&password=herring-barrel-42

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

HTTPS меняет транспорт и ничего выше него:

HTTPHTTPS
Порт по умолчанию80443
Схема в URLhttp://https://
В сетиЧитаемый текстЗашифрованные записи
Личность сервераНе проверяетсяПодтверждена сертификатом
Подмена данныхНезаметнаРазрывает соединение

Приложение не меняется. Тот же серверный код, тот же HTML, те же cookie - TLS оборачивает соединение, а HTTP работает внутри, ничего не замечая. Поэтому же "SSL" и "TLS" употребляют как синонимы: SSL был исходным протоколом 1990-х, TLS - его преемник, а все версии SSL официально списаны как небезопасные. То, что сегодня называют "SSL-сертификатом", используется только с TLS, а актуальные версии - TLS 1.2 и TLS 1.3. TLS 1.0 и 1.1 признаны устаревшими в 2021 году, и современные браузеры их не принимают.

Два вида шифрования, которые он использует#

HTTPS сочетает два семейства криптографии, потому что каждое сильно там, где другое слабо.

Симметричное шифрование использует один ключ и для закрытия, и для открытия. Оно достаточно быстрое, чтобы шифровать видео в реальном времени на телефоне. Слабое место очевидно: у обеих сторон должен быть один и тот же ключ, а отправить ключ по той самой сети, которую вы пытаетесь защитить, просто так нельзя. На практике используются шифры AES в режиме GCM и ChaCha20-Poly1305; оба заодно обнаруживают любое изменение данных, так что ловят не только прослушивание, но и подмену.

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

Поэтому HTTPS один раз в начале использует медленный и хитрый вид, чтобы договориться о ключе и проверить личность, а для всего остального - быстрый. Шаг договорённости называется обменом ключами; на практике это вариант Диффи - Хеллмана на эллиптических кривых, например X25519. Каждая сторона выбирает случайный секрет, отправляет значение, полученное из него, и обе стороны, объединив полученное со своим секретом, приходят к одному и тому же числу. Наблюдатель, видевший оба значения при передаче, всё равно не может его вычислить.

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

Сертификаты и центры сертификации#

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

Сертификат - это небольшой файл, который связывает открытый ключ с одним или несколькими именами. Его важные поля:

  • Subject alternative names - имена хостов, для которых он действителен, например example.com и www.example.com, или wildcard вроде *.example.com, покрывающий один уровень поддоменов.
  • Открытый ключ - открытая половина пары ключей, закрытая половина которой хранится на сервере.
  • Срок действия - даты "не раньше" и "не позже". Вне этого окна сертификат отклоняется.
  • Издатель и подпись - какой центр ручается за эту связку и его цифровая подпись под всем перечисленным.

Главное здесь - центр. Центр сертификации (CA) - это организация, чьи открытые ключи поставляются внутри вашей операционной системы или браузера, в списке под названием корневое хранилище (root store). Mozilla, Apple, Microsoft и Google ведут каждая своё и проверяют входящие в него центры. Когда CA подписывает сертификат, он заявляет, что проверил: заявитель управляет этим именем. Для бесплатных сертификатов, которыми пользуется большинство сайтов, эта проверка автоматическая: CA просит заявителя опубликовать токен на домене и забирает его - как именно проходит эта проверка, разобрано в статье HTTPS и Let's Encrypt: как это работает.

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

подписываетподписываетсоответствуетКорневой CAвстроен в браузерПромежуточный CAподписан корневымВаш сертификатexample.comЗакрытый ключне покидает сервер
Браузер доверяет корню и идёт вниз

Браузер проверяет каждую подпись вверх, пока не дойдёт до корня, которому уже доверяет. Если какого-то звена нет, оно просрочено или подписано неизвестно кем, соединение отклоняется с предупреждением. Сервер, который отправляет только свой сертификат и забывает промежуточный, - классическая ошибка настройки, и она раздражает тем, что в одних браузерах всё работает (в тех, что закэшировали промежуточный сертификат с другого сайта), а в других нет.

Каждый публичный сертификат также записывается в журналы Certificate Transparency - публичные журналы, доступные только для добавления, по которым может искать любой. Браузеры требуют доказательство, что сертификат попал в журнал. В результате CA не может тихо выпустить сертификат на ваш домен кому-то другому, не оставив следа, который вы можете найти.

TLS-рукопожатие по шагам#

Когда вы открываете https://example.com, перед получением первого байта HTML происходит следующее. Описан TLS 1.3, который согласует почти каждый современный браузер и сервер; TLS 1.2 следует той же логике с одним лишним обменом.

  1. TCP-соединение. Браузер определяет адрес через DNS и открывает соединение с портом 443 по этому адресу. (Поиск адреса разобран в статье DNS-записи: что это и как работают.)
  2. ClientHello. Браузер отправляет поддерживаемые версии TLS и шифры, случайное значение, свою половину обмена ключами ("key share") и два важных расширения: SNI - имя хоста, которое ему нужно, чтобы сервер с множеством сайтов знал, какой сертификат предъявить, и ALPN - протоколы, на которых он может говорить, например h2 для HTTP/2.
  3. ServerHello. Сервер выбирает версию и шифр и отправляет свою половину key share. В этот момент обе стороны могут вычислить один и тот же секрет, и всё дальше шифруется.
  4. Certificate. Сервер отправляет свой сертификат и цепочку промежуточных.
  5. CertificateVerify. Сервер подписывает своим закрытым ключом хеш всего разговора до этого момента. Это и есть доказательство личности: такую подпись мог создать только владелец закрытого ключа, соответствующего сертификату, а поскольку она охватывает случайные значения именно этого разговора, её нельзя воспроизвести из старого.
  6. Finished. Сервер отправляет короткое контрольное значение по всему рукопожатию, доказывающее, что при передаче ничего не изменили.
  7. Проверки клиента. Браузер проверяет цепочку до доверенного корня, даты, что имя в адресной строке есть в списке имён сертификата, и подпись из шага 5. Любой сбой останавливает соединение здесь, со страницей предупреждения.
  8. Client Finished, затем HTTP. Браузер отправляет своё сообщение Finished, а сразу за ним обычный запрос GET - уже внутри зашифрованных записей.
версии, SNI, ALPNдальше всё шифруетсяFinishedclient FinishedБраузерClientHello + key shareСерверServerHello + key shareСертификатцепочка + подписьПроверка браузерацепочка, имя, датыШифрованный HTTPGET / и страница
Рукопожатие TLS 1.3 за один обмен

Всё это стоит одного сетевого обмена до отправки запроса - примерно как один ping до сервера. Вернувшийся посетитель может возобновить прежнюю сессию и пропустить шаг с сертификатом, а TLS 1.3 при возобновлении даже позволяет отправлять данные в самом первом пакете ("0-RTT") ценой того, что эти ранние данные можно воспроизвести повторно, поэтому серверы принимают их только для запросов, которые безопасно повторять.

Настоящее рукопожатие можно посмотреть из терминала:

bash
# Summary: protocol, cipher, certificate subject and issuer$ openssl s_client -connect example.com:443 -servername example.com -brief < /dev/null# The same from curl, with every TLS step printed$ curl -v https://example.com -o /dev/null

Флаг -servername задаёт SNI. Без него сервер с несколькими именами может отдать сертификат по умолчанию от какого-то другого сайта, и результат выглядит как сломанный сертификат, хотя на деле просто не хватает флага.

HTTP/3 меняет транспорт под собой - он работает поверх QUIC по UDP-порту 443, а не по TCP, - но рукопожатие TLS 1.3 встроено в QUIC, и описанные выше шаги всё равно происходят.

Что означает замок и чего он не означает#

Замок, а в современном Chrome нейтральный значок настроек на том же месте, означает ровно три вещи: соединение зашифровано, при передаче оно не изменено, а сервер доказал, что у него есть действующий сертификат на имя из адресной строки. Это утверждение о канале, а не о людях на другом конце.

Он не означает, что:

  • Сайт честный. Фишинговая страница на paypa1-secure-login.com получает действующий сертификат за секунды, потому что сертификат лишь подтверждает контроль над этим конкретным именем. Читайте имя, а не значок.
  • Компания та, за кого себя выдаёт. Бесплатные распространённые сертификаты проверяют только домен. Более дорогие сертификаты с проверкой организации и расширенной проверкой (EV) предполагают сверку данных компании, но браузеры больше не показывают название компании в адресной строке, так что посетитель не может их отличить.
  • Сайт защищён. HTTPS защищает данные при передаче. Он ничего не делает с устаревшим плагином, слабым паролем администратора или базой данных, оставленной открытой в интернет. Лучше о защите этой стороны рассказано в статье Защита WordPress: как закрыть основные дыры.
  • Никто не видит, что вы заходили на сайт. Наблюдатель в сети по-прежнему видит IP-адрес сервера и, как правило, имя хоста: SNI в ClientHello отправляется в открытом виде, если только браузер и сервер оба не поддерживают Encrypted Client Hello, который пока внедряется, а DNS-запрос идёт открытым текстом, если устройство не использует зашифрованный DNS. Чего он не видит - это путь, строку запроса, заголовки, cookie и содержимое. Адрес https://example.com/account/orders?id=4411 выдаёт example.com, а остальное остаётся внутри туннеля.
  • Ваш работодатель или учебное заведение не может это прочитать. Корпоративные сети и некоторые антивирусы устанавливают на управляемые устройства собственный корневой сертификат и намеренно расшифровывают трафик посередине. На устройстве, которое вы не контролируете, считайте это возможным. Как это пересекается с VPN, разобрано в статье Что защищает VPN, а что нет.

HSTS: закрываем брешь первого запроса#

Даже у сайта, который перенаправляет каждый HTTP-запрос на HTTPS, есть слабый момент: самый первый запрос. Если вы набираете example.com, браузер сначала пробует http://, и этот открытый запрос могут перехватить до прихода перенаправления. Злоумышленник в той же сети wifi может ответить на него сам и бесконечно держать вас на HTTP - это атака понижения (downgrade).

HSTS (HTTP Strict Transport Security) закрывает эту брешь. Сервер один раз отправляет заголовок по HTTPS:

code
Strict-Transport-Security: max-age=31536000; includeSubDomains

С этого момента в течение max-age секунд - здесь это год - браузер перед отправкой переписывает каждую ссылку http:// на это имя в https:// и убирает возможность пройти дальше при предупреждении о сертификате. Первый визит всё же остаётся незащищённым, и для этого существует список preload: имена, отправленные в него, зашиваются в браузеры как доступные только по HTTPS ещё до первого визита. Некоторые целые домены верхнего уровня, например .dev и .app, входят в этот список, поэтому любой сайт под ними должен работать по HTTPS с первого дня.

HSTS - единственная возможность HTTPS, которая может закрыть вам доступ к собственному сайту, если какому-то поддомену всё ещё нужен обычный HTTP, а preload отменяется медленно. Начните с короткого max-age, убедитесь, что всё работает, и только потом увеличивайте. Настройка, а также перенаправление и очистка смешанного содержимого, с которых стоит начинать, описаны в статье HTTPS и Let's Encrypt: как это работает.

Зачем HTTPS каждому сайту#

"На моём сайте нет входа и нет платежей" - обычный довод против того, чтобы заморачиваться. Сегодня он не выдерживает критики, причём по причинам, не связанным с секретностью.

  • Браузеры помечают обычный HTTP как небезопасный в адресной строке на каждой странице. Формы на страницах по HTTP получают дополнительное предупреждение, когда человек начинает вводить текст, а браузеры всё чаще сначала пробуют HTTPS и предупреждают перед возвратом к обычному HTTP.
  • Подмена касается и скучных страниц. Внедрённый скрипт на статичном кулинарном блоге выполняется в браузере посетителя с теми же правами, что и ваш: он может перенаправить, майнить или показать поддельное окно входа.
  • Современные возможности требуют его. Геолокация, доступ к камере и микрофону, service workers, push-уведомления, API буфера обмена и HTTP/2 в браузерах - всё это требует безопасного контекста. Браузеры используют HTTP/2 и HTTP/3 только поверх TLS, так что сайт только по HTTP ещё и застрял на более старом и медленном протоколе.
  • Поисковые системы предпочитают его. Google использует HTTPS как фактор ранжирования с 2014 года. Это небольшой фактор, но он ничего не стоит.
  • Данные о реферере сохраняются. Когда посетитель переходит со страницы HTTPS на страницу HTTP, браузер удаляет реферер, поэтому сайты по HTTP теряют часть аналитики.
  • Сертификат бесплатный и обновляется сам. Довод о стоимости исчез, когда бесплатные автоматические сертификаты стали нормой.

На тарифах RE:NODE для приложений и сайтов всё сводится к одной DNS-записи: добавьте имя хоста в слот прокси, направьте A-запись на показанный адрес, и сертификат будет выпущен, как только имя начнёт разрешаться, и обновляется автоматически в окне 21 день. Прокси завершает TLS и передаёт вашему приложению обычный HTTP, а настоящий адрес посетителя - в X-Forwarded-For. Как это настроить и почему выпуск иногда не удаётся, описано в статье Направьте домен на сервер и добавьте SSL.

Ошибки сертификата и что они значат#

Большинство проблем с HTTPS проявляются как одна из нескольких ошибок браузера. Коды в разных браузерах отличаются, причины одинаковы.

Chrome / EdgeFirefoxПричина
NET::ERR_CERT_DATE_INVALIDSEC_ERROR_EXPIRED_CERTIFICATEСрок истёк или неверные часы на устройстве
NET::ERR_CERT_COMMON_NAME_INVALIDSSL_ERROR_BAD_CERT_DOMAINИмени нет в сертификате
NET::ERR_CERT_AUTHORITY_INVALIDSEC_ERROR_UNKNOWN_ISSUERЦепочка неполная или не вызывает доверия

Срок истёк. Либо не удалось обновить сертификат на сайте, либо на устройстве посетителя неверные часы. Телефон или ПК с датой на несколько лет в прошлом отвергает сразу все сертификаты в интернете, и это выдаёт причину: если ломаются все сайты, проверьте часы.

Неверное имя. Сертификат выпущен на example.com, а посетитель пришёл через www.example.com, или новый поддомен направили на сервер до того, как для него выпустили сертификат. Сертификат действителен только для имён, перечисленных в нём.

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

Небезопасно, хотя сертификат действителен. Смешанное содержимое: страница по HTTPS, но загружает скрипт, стили или изображение по http://. Браузеры блокируют активное содержимое полностью, и страница отображается наполовину. Точный URL указан в консоли браузера.

`ERR_TOO_MANY_REDIRECTS`. Обычно это приложение за прокси, завершающим TLS: оно видит обычный HTTP на своём порту и продолжает перенаправлять на HTTPS. Приложению нужно вместо этого доверять заголовку X-Forwarded-Proto от прокси. Почему так, объясняет статья Что делает обратный прокси.

Чтобы проверить, как сайт ведёт себя снаружи, на большинство вопросов отвечают две команды:

bash
# Does HTTP redirect to HTTPS, and to which host?$ curl -sI http://example.com | grep -iE "^(HTTP|location)"# Is HSTS set, and for how long?$ curl -sI https://example.com | grep -i strict-transport-security

FAQ#

HTTPS и SSL - это одно и то же?

В обиходе да. Технически HTTPS - это HTTP, переданный поверх TLS, а TLS заменил SSL в 1999 году. Все версии SSL теперь списаны как небезопасные, но старое название прижилось, поэтому сертификаты по-прежнему продают как "SSL-сертификаты". Работают они с TLS 1.2 и 1.3.

HTTPS замедляет сайт?

На современном оборудовании заметно нет. Рукопожатие добавляет один обмен на новом соединении и меньше на возобновлённом, а само шифрование выполняется специальными инструкциями процессора. На практике сайты по HTTPS нередко быстрее, потому что браузеры используют HTTP/2 и HTTP/3 только поверх TLS.

Видит ли мой провайдер, какие сайты я посещаю по HTTPS?

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

Как долго действует сертификат?

Бесплатные сертификаты Let's Encrypt действуют 90 дней и обновляются автоматически. Максимальный срок для любого публично доверенного сертификата в отрасли неоднократно сокращали, и в ближайшие годы он продолжит уменьшаться, поэтому ручное ежегодное обновление повсеместно уходит в прошлое.

Достаточно ли самоподписанного сертификата?

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

Нужен ли HTTPS для игрового сервера?

Для самого игрового трафика нет - Minecraft, Valheim и большинство игр используют собственные протоколы на собственных портах, а не HTTP. Он нужен для всего, что связано с игрой и открыто в вебе: сайта, просмотрщика карты, страницы пожертвований или панели.