SNI-фильтрация против TLS-маскировки: разбор механики и реальные грабли
Содержание
Что такое SNI и зачем он нужен
SNI (Server Name Indication) — расширение TLS, появившееся в 2003 году. Решает простую задачу: сервер должен понять, какой сайт запрашивает клиент, если на одном IP живёт сотня доменов. До SNI серверу приходилось отдавать один сертификат на всё — неудобно.
Технически: клиент вставляет имя хоста в открытом виде в первый пакет TLS handshake — ClientHello. Поле называется `server_name`, идёт после версии протокола и случайных чисел. Без шифрования. Это ключевой момент.
```bash
openssl s_client -connect example.com:443 -servername example.com -tlsextdebug 2>&1 | grep "server_name"
```
Вывод покажет строку вида `server_name=example.com`. Любой промежуточный узел видит это поле. Именно на этом построена SNI-фильтрация.
Как работает фильтрация на практике
Провайдер ставит DPI (Deep Packet Inspection) на магистральных каналах. Устройство анализирует первые байты TLS-потока. Если в ClientHello встречается домен из реестра запрещённых — соединение рвётся.
Три способа разрыва:
1. **RST-пакет** — принудительный сброс соединения. Быстро, но клиент видит ошибку.
2. **Blackhole** — пакеты молча дропаются. Соединение висит до таймаута.
3. **HTTP redirect** — для незашифрованных запросов. К TLS не применяется.
Реестр доменов собирается автоматически. РосКомнадзор использует систему Ревизор, которая ходит по сайтам и вытаскивает SNI из трафика. Потом эти домены попадают в выгрузку для операторов.
Почему VPN с маскировкой TLS пасует
Тут начинается самое интересное. VPN-клиент с маскировкой TLS отправляет свой трафик внутри обычного TLS-соединения. Идея: DPI видит ClientHello, не находит там запрещённого домена — пропускает. Работает, но есть нюансы.
Первый нюанс — **статистический анализ**. DPI не просто смотрит на SNI. Он анализирует:
- размер пакетов;
- тайминги между пакетами;
- длину сессии;
- поведение после handshake.
Обычный HTTPS-запрос к веб-серверу — это короткие запросы-ответы. VPN-туннель — это постоянный поток данных в обе стороны с равными интервалами. Отличие видно по характеру трафика.
Второй нюанс — **проверка сертификата**. DPI может сделать активное подключение к серверу и проверить, какой сертификат тот отдаёт. Если сертификат не соответствует SNI или выпущен неизвестным CA — соединение подозрительное. Свежие версии DPI умеют это делать.
Реальные кейсы
Кейс: публичные SNI-прокси
Проблема: пользователи массово использовали публичные TLS-прокси типа `proxy.example.com`. Провайдер занёс домен в реестр. Все подключения умерли за час.
Причина: DPI увидел, что с одного IP идут тысячи одновременных TLS-соединений с одинаковым SNI. Автоматика добавила домен в список.
Решение: переезд на новый домен каждые 2-3 дня. Костыль, но работал до тех пор, пока провайдер не начал анализировать поведение с помощью ML-моделей.
Кейс: CDN-обход
Проблема: сайт заблокирован, но он стоит за Cloudflare. Пользователи подключались к IP Cloudflare и слали запросы с SNI заблокированного домена.
Причина: DPI пропускал трафик к IP Cloudflare, так как сам Cloudflare не в реестре. Но SNI внутри ClientHello всё равно содержал запрещённый домен.
Решение: провайдеры начали фильтровать по связке "IP:SNI". Если на IP Cloudflare приходит SNI запрещённого домена — соединение рвётся. Обход перестал работать.
Кейс: TLS в TLS
Проблема: VPN с маскировкой TLS внутри TLS. Внешний слой — обычный HTTPS к легитимному серверу. Внутренний — VPN-туннель.
Причина: DPI видит двойной TLS handshake. Сначала ClientHello к легитимному серверу, потом внутри — ещё один ClientHello. Такая структура не встречается в обычном HTTPS-трафике.
Решение: провайдеры добавили правило "TLS внутри TLS = блокировка". VPN-провайдеры перешли на другие протоколы маскировки, но это уже другая история.
Как обойти фильтрацию
Полностью защититься от SNI-фильтрации сложно, но есть рабочие методы.
ESNI и ECH
Encrypted Client Hello (ECH) — расширение TLS 1.3, шифрующее SNI. Клиент и сервер заранее обмениваются ключами через DNS. DPI не видит SNI, видит только IP-адрес.
```bash
curl --tlsv1.3 --tls-max 1.3 --ech hard https://example.com
```
Проблема: ECH требует поддержки на стороне сервера. Из крупных игроков — Cloudflare и Fastly. Провайдеры тоже не дремлют — анализируют DNS-запросы для получения ключей ECH.
SNI-фрагментация
Разбивка ClientHello на несколько TCP-пакетов. DPI собирает поток, но если фрагменты приходят с задержкой — анализатор может не успеть распознать домен.
```python
import socket
def send_fragmented_client_hello(ip, port, data):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((ip, port))
mid = len(data) // 2
sock.send(data[:mid])
time.sleep(0.5)
sock.send(data[mid:])
```
Метод работает против старых DPI. Современные анализаторы собирают фрагменты и ждут завершения handshake.
Домены-приманки
Использование легитимного домена с поддержкой SNI-проксирования. Например, сервер на nginx принимает запросы для одного домена, а внутри перенаправляет на VPN-сервер.
```nginx
stream {
server {
listen 443;
ssl_preread on;
map \$ssl_preread_server_name \$backend {
vpn.example.com vpn_backend;
default web_backend;
}
}
}
```
DPI видит легитимный домен в SNI, но трафик уходит на VPN. Работает, пока провайдер не начнёт анализировать поведение после handshake.
Что дальше
SNI-фильтрация эволюционирует. В 2024 году активно внедряются ML-модели, которые анализируют не только SNI, но и поведенческие паттерны. VPN-провайдеры отвечают новыми протоколами маскировки.
Реальный совет: если нужен стабильный обход, выбирайте провайдера с собственными протоколами маскировки, а не просто TLS-обёрткой. Публичные решения умирают быстро. Собственные протоколы живут дольше, но и они не вечны.
На практике хороший вариант — комбинировать ECH с фрагментацией и менять домены. Это не даёт 100% гарантии, но поднимает порог обнаружения. Для большинства задач этого достаточно.