SNI
| Полное название | Server Name Indication |
|---|---|
| Спецификация | RFC 3546 (2003), действующая — RFC 6066 |
| Где передаётся | в сообщении ClientHello рукопожатия TLS |
| Назначение | виртуальный хостинг HTTPS на одном IP-адресе |
| Видимость | открытым текстом (кроме ECH) |
| Шифрование имени | Encrypted Client Hello (ECH) |
SNI (англ. Server Name Indication — указание имени сервера) — расширение протокола TLS, с помощью которого клиент в самом первом сообщении рукопожатия (ClientHello) сообщает, к какому доменному имени он подключается. Сервер, обслуживающий много сайтов на одном IP-адресе, по этому имени выбирает нужный сертификат и конфигурацию.[1]
Без SNI каждому HTTPS-сайту требовался бы отдельный IP-адрес. Сегодня SNI отправляют все браузеры и HTTP-клиенты, и именно он позволяет хостингам, CDN и обратным прокси обслуживать тысячи доменов на общих адресах.
Проблема, которую решает SNI
В обычном HTTP сервер узнаёт сайт из заголовка Host, поэтому на одном адресе легко размещать много сайтов (виртуальный хостинг). В HTTPS заголовок Host передаётся уже внутри зашифрованного канала, а чтобы установить канал, сервер должен сначала предъявить сертификат — но какой, если он ещё не знает, какой сайт нужен клиенту? SNI решает это, передавая имя до выбора сертификата.
Расширение описано в RFC 3546 в 2003 году, а сейчас — в RFC 6066.[2] Долгое время массовому использованию мешали старые клиенты — Internet Explorer на Windows XP и ранние версии Android, — но с их уходом SNI стал универсальным.
Как это выглядит
# подключиться к IP-адресу, указав имя сайта для SNI
openssl s_client -connect 203.0.113.10:443 -servername example.com </dev/null | head -20
# curl сам отправляет SNI по имени из URL; --resolve подставляет IP
curl -v --resolve example.com:443:203.0.113.10 https://example.com
Если не указать -servername, сервер вернёт сертификат по умолчанию, и проверка имени, скорее всего, не пройдёт — частая причина недоумения при отладке.
На стороне сервера выбор по SNI происходит автоматически. В nginx достаточно нескольких блоков server с разными server_name и сертификатами на одном порту:[5]
server {
listen 443 ssl;
server_name shop.example.com;
ssl_certificate /etc/ssl/shop.crt;
ssl_certificate_key /etc/ssl/shop.key;
}
server {
listen 443 ssl;
server_name blog.example.com;
ssl_certificate /etc/ssl/blog.crt;
ssl_certificate_key /etc/ssl/blog.key;
}
Приватность: SNI виден всем
SNI передаётся открытым текстом: TLS 1.3 зашифровал сертификат сервера и почти всё рукопожатие, но имя в ClientHello осталось видимым.[6] Провайдер, администратор сети или любой наблюдатель видит, на какие сайты ходит пользователь, даже не видя содержимого. Этим пользуются системы фильтрации трафика (DPI) для блокировки отдельных сайтов, корпоративные прокси и системы обнаружения угроз. Тот же эффект дают незашифрованные запросы DNS.
Encrypted Client Hello
Первая попытка скрыть имя — ESNI (2018) — шифровала только расширение SNI. Её заменила более общая схема Encrypted Client Hello (ECH): клиент шифрует весь «внутренний» ClientHello с настоящим именем открытым ключом, опубликованным в DNS-записи HTTPS (см. DNS-записи (A, AAAA, CNAME, MX, TXT)), а во «внешнем» ClientHello указывает общее имя фронтенд-сервера.[3] Наблюдатель видит только, что пользователь обращается, например, к CDN, но не к какому из тысяч сайтов за ним.
ECH поддерживают Firefox и Chrome и крупные CDN.[4] Для полной приватности его нужно сочетать с зашифрованным DNS (DoH, DoT), иначе имя утечёт через DNS-запрос.
Связанные темы
- Маршрутизация по SNI без расшифровки. Балансировщики и прокси (HAProxy, nginx
streamсssl_preread) читают SNI из ClientHello и направляют TCP-соединение на нужный бэкенд, не завершая TLS. - Domain fronting — приём, когда в SNI указан один домен CDN, а в зашифрованном заголовке
Host— другой; использовался для обхода блокировок, сейчас большинство CDN его запрещают. - Несовпадение SNI и сертификата — браузер покажет ошибку «сертификат выдан для другого имени»; проверьте
server_nameи поле SAN сертификата (см. Сертификат X.509 и центры сертификации).
См. также
Источники
- RFC 6066 — TLS Extensions: Extension Definitions (Server Name Indication)
- RFC 3546 — Transport Layer Security (TLS) Extensions
- IETF — TLS Encrypted Client Hello (draft-ietf-tls-esni)
- Cloudflare Blog — Encrypted Client Hello: the last puzzle piece to privacy
- nginx — Server names
- RFC 8446 — The Transport Layer Security (TLS) Protocol Version 1.3