Проблема одного адреса и множества сайтов
На одном IP-адресе часто размещаются сотни сайтов. В обычном HTTP сервер узнаёт нужный сайт из заголовка Host. Но при HTTPS сообщение с этим заголовком идёт уже внутри шифрованного канала, а чтобы установить канал, серверу нужно предъявить сертификат, причём именно для запрошенного домена. Получается замкнутый круг: чтобы выбрать сертификат, нужно знать домен, а домен известен только из зашифрованного запроса.
Расширение SNI, Server Name Indication, разрывает круг просто: клиент в самом начале рукопожатия TLS, в сообщении ClientHello, называет имя сайта. Сервер выбирает подходящий сертификат и продолжает согласование.
Как это выглядит в рукопожатии
Сообщение ClientHello отправляется до того, как появился общий ключ, поэтому расширение SNI в нём передаётся открытым текстом. Сервер читает имя, находит сертификат этого домена и высылает его. Если имени нет или оно не подходит, сервер может вернуть сертификат по умолчанию или отказать, что в браузере приводит к ошибке о несовпадении имени сертификата.
Поддержка SNI появилась в 2000-х, и первое время часть старых систем, вроде очень ранних версий Android и Windows XP с Internet Explorer, её не понимала. Сегодня практически всё современное программное обеспечение работает с ней, а её отсутствие встречается лишь в самом устаревшем оборудовании.
Смежная деталь — расширение ALPN в том же сообщении. Оно позволяет клиенту сразу предложить список прикладных протоколов, например h2 и http/1.1, и сервер выбирает подходящий. Так одно рукопожатие решает сразу две задачи: выбор сертификата по имени и выбор версии HTTP, без дополнительных кругов обмена.
Что видит наблюдатель и на что это влияет
Поскольку имя передаётся открыто, наблюдатель на маршруте, будь то провайдер, администратор сети или владелец публичной точки Wi-Fi, может узнать, к какому домену вы подключаетесь, хотя содержимого страниц, путей и cookie не увидит. Тем же пользуются сетевые фильтры в организациях и родительский контроль: их правила часто сопоставляют домен из SNI со списком категорий.
К похожим сведениям относится и запрос DNS, если он не зашифрован: то, что у SNI видно имя в TLS, у обычного DNS видно имя в запросе. Об этом рассказано на страницах про DNS и DNS over HTTPS. Таким образом, «HTTPS шифрует всё» верно лишь для содержимого, но не для адресата.
ECH и другие способы скрыть имя
Для закрытия этой лазейки разработано расширение Encrypted Client Hello, ECH. Оно шифрует внутреннюю часть ClientHello, включая настоящее имя, ключом, публикуемым сервером обычно в записи DNS. Наблюдатель видит только общее имя внешнего слоя, часто это имя провайдера сети доставки контента, обслуживающего множество сайтов.
Эффективность ECH зависит от поддержки на обеих сторонах, а также от защиты самого запроса DNS: если ключ или имя запрашиваются открыто, преимущество уменьшается. Поддержка появляется в браузерах и у части сетей доставки контента, но распространена не повсеместно и включается по-разному. Для отдельных пользователей она может оказаться выключенной по умолчанию.
Заблуждения и как посмотреть SNI самому
Ошибочно думать, что при HTTPS провайдер видит лишь IP-адрес. Он видит и адрес, и домен из SNI, пока ECH не применяется. Ошибочно и обратное: что видны страницы, которые вы читаете. Пути, запросы и содержимое скрыты. Наконец, SNI нередко связывают с QUIC, но и там имя ClientHello передаётся, хотя и в зашифрованном начальном пакете с ключами, которые выводятся из публичных значений, так что его способен извлечь тот, кто знает, как.
Увидеть поле можно анализатором пакетов Wireshark: в пакете ClientHello раскройте раздел расширений и найдите server_name. Из командной строки проверку сертификата для нужного имени выполняет openssl s_client с параметром -servername: сравнив ответы с разными именами, легко заметить, что один IP отдаёт разные сертификаты.