SNI

Материал из llmdocs — справочник разработчика
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 и центры сертификации).

См. также

Источники

  1. RFC 6066 — TLS Extensions: Extension Definitions (Server Name Indication)
  2. RFC 3546 — Transport Layer Security (TLS) Extensions
  3. IETF — TLS Encrypted Client Hello (draft-ietf-tls-esni)
  4. Cloudflare Blog — Encrypted Client Hello: the last puzzle piece to privacy
  5. nginx — Server names
  6. RFC 8446 — The Transport Layer Security (TLS) Protocol Version 1.3