SNI (Server Name Indication) — це розширення TLS, яке дозволяє клієнту вказувати ім'я хоста, до якого він намагається підключитися під час рукостискання TLS, що дозволяє проксі-серверам правильно маршрутизувати або термінувати TLS-з'єднання для кількох доменів, розміщених на одній IP-адресі.
До SNI сервер вимагав унікальної IP-адреси для кожного сертифіката SSL, якщо на одному сервері розміщувалося кілька безпечних веб-сайтів. Це обмеження виникло через те, що рукостискання TLS відбувалося до надсилання заголовка HTTP Host, що не дозволяло серверу знати, який сертифікат представити. SNI, визначений у RFC 6066, вирішує цю проблему, включаючи бажане ім'я хоста в повідомлення ClientHello, дозволяючи серверу (або проксі-серверу) вибрати правильний сертифікат та конфігурацію.
Як працює SNI
Клієнт включає цільове ім'я хоста в поле extension_data розширення server_name у повідомленні ClientHello. Це відбувається до обміну будь-якими зашифрованими даними та до того, як сервер представить свій сертифікат.
ClientHello
Version: TLS 1.2
Random: ...
Session ID: ...
Cipher Suites: ...
Extensions:
...
Server Name (SNI)
Server Name Type: host_name (0)
Server Name: example.com
...
Сервер або проміжний проксі-сервер отримує це ClientHello і може витягти ім'я хоста example.com. Ця інформація потім використовується для визначення того, який сертифікат TLS представити та як маршрутизувати або обробити подальше з'єднання.
Обробка SNI проксі-серверами
Проксі-сервери взаємодіють з SNI по-різному залежно від їхнього типу, режиму роботи та того, чи виконують вони термінацію TLS або наскрізну передачу.
Прозорі проксі-сервери
Прозорий проксі-сервер перехоплює трафік без явного налаштування клієнта на його використання. Для TLS-трафіку прозорий проксі-сервер часто працює на Рівні 4 (TCP). Він зазвичай пересилає необроблений потік TCP, включаючи повідомлення ClientHello з SNI, безпосередньо на цільовий сервер.
- Видимість SNI: Прозорий проксі-сервер може перевіряти повідомлення
ClientHello, щоб витягти ім'я хоста SNI. Це дозволяє здійснювати базову маршрутизацію, ведення журналів або правила фільтрації на основі домену призначення, навіть якщо саме корисне навантаження залишається зашифрованим. - Термінація TLS: Прозорі проксі-сервери зазвичай не термінують TLS для клієнта, якщо вони спеціально не налаштовані для глибокої перевірки пакетів (DPI) або операцій "людина посередині" (MITM), що вимагає довіри клієнта до кореневого ЦС проксі-сервера. У стандартній прозорій конфігурації проксі-сервер передає
ClientHelloвихідному серверу, який потім виконує рукостискання TLS безпосередньо з клієнтом.
Прямі проксі-сервери
Прямий проксі-сервер діє як посередник для клієнтів, які запитують ресурси із зовнішніх серверів. Клієнти явно налаштовані на використання прямого проксі-сервера.
Метод CONNECT
Для HTTPS-трафіку клієнти зазвичай використовують метод HTTP CONNECT, щоб наказати прямому проксі-серверу встановити TCP-тунель до цільового сервера.
CONNECT example.com:443 HTTP/1.1
Host: example.com:443
Proxy-Connection: Keep-Alive
Після успішного виконання запиту CONNECT (проксі-сервер відповідає HTTP/1.1 200 Connection established) клієнт ініціює рукостискання TLS безпосередньо з цільовим сервером через встановлений тунель.
- Видимість SNI (без перехоплення): У цьому режимі прямий проксі-сервер зазвичай не обробляє значення SNI з повідомлення
ClientHello, оскільки він просто ретранслює необроблений зашифрований потік TCP. ЗапитCONNECTнадає ім'я хоста призначення, яке проксі-сервер використовує для маршрутизації. - Термінація TLS: Проксі-сервер не термінує TLS; рукостискання TLS відбувається наскрізно між клієнтом та вихідним сервером.
Перехоплення TLS (MITM)
Деякі прямі проксі-сервери налаштовані на перехоплення TLS (також відоме як перевірка SSL або проксіювання MITM). Це передбачає термінацію TLS-з'єднання клієнта проксі-сервером та встановлення нового TLS-з'єднання з вихідним сервером.
- Клієнт ініціює рукостискання TLS з проксі-сервером: Клієнт надсилає
ClientHelloпроксі-серверу. - Проксі-сервер витягує SNI: Проксі-сервер зчитує ім'я хоста SNI з
ClientHello. - Проксі-сервер генерує сертифікат: Використовуючи власний сертифікат ЦС (якому довіряє клієнт), проксі-сервер динамічно генерує сертифікат сервера для імені хоста SNI.
- Проксі-сервер завершує рукостискання з клієнтом: Проксі-сервер представляє згенерований сертифікат клієнту.
- Проксі-сервер встановлює нове TLS-з'єднання з вихідним сервером: Проксі-сервер ініціює нове рукостискання TLS з фактичним вихідним сервером, використовуючи витягнуте ім'я хоста SNI у своєму
ClientHello. - Проксі-сервер розшифровує/повторно шифрує трафік: Проксі-сервер розшифровує трафік клієнта, перевіряє його, а потім повторно шифрує його перед надсиланням на вихідний сервер, і навпаки.
- Використання SNI: SNI є критично важливим для перехоплення TLS. Проксі-сервер використовує значення SNI для:
- Визначення, яке ім'я хоста імітувати для клієнта.
- Визначення, яке ім'я хоста запитувати від вихідного сервера.
- Наслідки для безпеки: Вимагає від клієнта довіряти кореневому ЦС проксі-сервера. Цей режим надає проксі-серверу повну видимість зашифрованого трафіку.
Зворотні проксі-сервери
Зворотний проксі-сервер знаходиться перед одним або кількома веб-серверами, направляючи запити клієнтів до відповідного бекенд-сервера. Клієнти підключаються до зворотного проксі-сервера, не знаючи про архітектуру бекенду.
- Використання SNI: Коли клієнт ініціює рукостискання TLS зі зворотним проксі-сервером, проксі-сервер отримує повідомлення
ClientHello, що містить ім'я хоста SNI. Зворотний проксі-сервер використовує це значення SNI для:- Вибору правильного сертифіката сервера для представлення клієнту, якщо він розміщує кілька доменів.
- Маршрутизації запиту до відповідного бекенд-сервера або пулу застосунків.
- Застосування політик для конкретних доменів (наприклад, правил WAF, кешування, балансування навантаження).
- Термінація TLS: Зворотні проксі-сервери майже завжди термінують TLS-з'єднання від клієнтів. Вони розшифровують трафік, обробляють його, а потім можуть повторно шифрувати його для зв'язку з бекенд-серверами (повторне шифрування або бекенд TLS).
Приклад: Зворотний проксі-сервер Nginx з SNI
http {
# Default server for requests without SNI or for unknown SNI
server {
listen 443 ssl default_server;
server_name _; # Catch-all
ssl_certificate /etc/nginx/ssl/default.crt;
ssl_certificate_key /etc/nginx/ssl/default.key;
return 404;
}
# Backend for example.com
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
location / {
proxy_pass https://backend_example_com;
proxy_ssl_server_name on; # Pass SNI to backend
}
}
# Backend for api.example.com
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/nginx/ssl/api.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/api.example.com.key;
location / {
proxy_pass https://backend_api_example_com;
proxy_ssl_server_name on; # Pass SNI to backend
}
}
}
У цій конфігурації Nginx директива server_name відповідає SNI, представленому клієнтом. Потім Nginx використовує відповідний ssl_certificate і маршрутизує запит до вказаного бекенду proxy_pass. proxy_ssl_server_name on гарантує, що Nginx включає ім'я хоста SNI при встановленні нового TLS-з'єднання з бекендом.
SNI та проксі-сервери Рівня 4 проти Рівня 7
Відмінність між проксі-серверами Рівня 4 (TCP) та Рівня 7 (Застосунків) також впливає на обробку SNI.
-
Проксі-сервери Рівня 4: Працюють на рівні TCP. Вони можуть перевіряти пакет
ClientHello, щоб витягти SNI без розшифровки всього TLS-потоку. Це дозволяє здійснювати маршрутизацію або фільтрацію на основі SNI до завершення рукостискання TLS, без необхідності термінувати TLS. HAProxy у режимі TCP може це виконувати.listen https_frontend bind *:443 mode tcp tcp-request inspect-delay 5s tcp-request content accept if { req_ssl_hello_type 1 } tcp-request content track-sc0 src # Route based on SNI use_backend backend_example_com if { req_ssl_sni -i example.com } use_backend backend_api_example_com if { req_ssl_sni -i api.example.com } default_backend backend_default
Ця конфігурація HAProxy використовуєreq_ssl_sniдля перевірки SNI зClientHelloта відповідної маршрутизації TCP-з'єднання, не термінуючи сам TLS. -
Проксі-сервери Рівня 7: Працюють на прикладному рівні (наприклад, HTTP/HTTPS). Вони повинні термінувати TLS для доступу до заголовків прикладного рівня (таких як HTTP Host, шлях URL тощо). Після термінації TLS вони використовують SNI з початкового
ClientHelloдля вибору правильного сертифіката сервера, а потім приступають до обробки розшифрованого HTTP-запиту. Зворотні проксі-сервери зазвичай є проксі-серверами L7. Прямі проксі-сервери, що виконують перехоплення TLS, також є L7.
Порівняння: Режими обробки SNI проксі-серверами
| Функція | Прозорий проксі-сервер (наскрізна передача L4) | Прямий проксі-сервер (CONNECT, без MITM) | Прямий проксі-сервер (перехоплення TLS/MITM) | Зворотний проксі-сервер (термінація TLS) |
|---|---|---|---|---|
| TLS клієнта завершується на | Вихідний сервер | Вихідний сервер | Проксі-сервер | Проксі-сервер |
| TLS проксі-сервера завершується на | Н/Д (наскрізна передача) | Н/Д (наскрізна передача) | Вихідний сервер | Н/Д (ініціює нове, якщо бекенд TLS) |
| Видимість SNI для проксі-сервера | Так (відкритий текст у ClientHello) | Ні (після CONNECT) | Так (відкритий текст у ClientHello) | Так (відкритий текст у ClientHello) |
| Використання SNI проксі-сервером | Маршрутизація, ведення журналів, базова фільтрація | Не безпосередньо з ClientHello | Генерація сертифікатів, вибір вихідного сервера | Вибір сертифікатів, маршрутизація, застосування політик |
| Проксі-сервер розшифровує трафік | Ні | Ні | Так | Так |
| Вимога довіри клієнта | Немає | Немає | Кореневий ЦС проксі-сервера | Сертифікат вихідного сервера (представлений проксі-сервером) |
Міркування щодо безпеки та конфіденційності
SNI, за задумом, передається у відкритому тексті в повідомленні ClientHello. Це означає, що мережеві посередники, включаючи проксі-сервери та інтернет-провайдерів, можуть спостерігати, до якого імені хоста клієнт намагається підключитися, навіть якщо решта TLS-зв'язку зашифрована.
Ця відкрита експозиція має наслідки для конфіденційності. Для вирішення цієї проблеми IETF розробила Encrypted SNI (ESNI), яка перетворюється на Encrypted Client Hello (ECH). ESNI/ECH шифрує розширення Server Name у повідомленні ClientHello, роблячи його непрозорим для пасивних спостерігачів.
- Вплив на проксі-сервери: ESNI/ECH значно змінює спосіб роботи проксі-серверів (особливо проксі-серверів L4 або тих, що виконують маршрутизацію на основі SNI без повної термінації TLS). Якщо SNI зашифрований, проксі-сервер не може використовувати його для рішень щодо маршрутизації у відкритому тексті. Проксі-сервери, що підтримують ESNI/ECH, повинні були б брати участь в обміні ключами або покладатися на інші механізми (наприклад, IP-адресу, DNS) для початкової маршрутизації, або розшифровувати ECH, якщо вони є передбаченою кінцевою точкою ECH. Для проксі-серверів, що термінують TLS (таких як зворотні проксі-сервери або прямі проксі-сервери MITM), їм все одно потрібно було б розшифрувати ECH, щоб дізнатися передбачене ім'я хоста для вибору сертифіката та маршрутизації.