Files
networking-proxy/references/tls-fingerprint-dpi-detection.md
2026-09-06 13:51:04 +00:00

133 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TLS Fingerprint — DPI Detection Technique
## Источник
Статья на Хабре: [Конец удобства? Почему MTProxy начал ломаться](https://habr.com/ru/articles/1018672/) (2 апреля 2026, s4q)
## Суть техники
DPI (Deep Packet Inspection) анализирует TLS ClientHello на предмет узнаваемого отпечатка (fingerprint). Отпечаток складывается из:
- Порядка cipher suites
- Списка TLS extensions
- Supported groups (elliptic curves)
- Signature algorithms
- Версии TLS
- Других параметров ClientHello
У каждого TLS-клиента (браузер, Telegram, curl) — уникальная комбинация этих параметров. DPI сравнивает её с базой известных fingerprint'ов и принимает решение: пропустить, деградировать (RST-инъекция) или дропнуть пакеты.
## Применимость к XRay Reality
XRay Reality принципиально отличается от MTProxy/Fake-TLS тем, что **не имитирует TLS, а использует настоящий TLS-сервер** (reddit.com, cloudflare.com и т.д.) как маскировку. Reality:
1. Принимает ClientHello от клиента
2. Проверяет REALITY-подпись (publicKey + shortId + время)
3. Если подпись невалидна — проксирует соединение на реальный сервер (dest), как обычный HTTPS
4. Если подпись валидна — расшифровывает VLESS-трафик
**Разница с MTProxy:** MTProxy использует Fake-TLS — сам отправляет поддельный ServerHello, не обращаясь к реальному серверу. У Reality — настоящий TLS-сервер на backend'е, поэтому поведение трафика после рукопожатия неотличимо от браузерного.
## Почему это важно для диагностики
Когда в логах XRay появляется `REALITY: failed to read client hello`, это может быть следствием:
1. **Неверный publicKey/shortId в клиенте** — DPI не при чём, чисто конфигурационная проблема
2. **DPI обрезает ClientHello на уровне сети** — пакет приходит повреждённым/обрезанным
3. **Клиент отправляет ClientHello с нестандартными параметрами** — например, из-за ошибки в реализации TLS
### Случай из статьи: баг в encrypted_client_hello Telegram
В коде генерации `encrypted_client_hello` у Telegram нашли ошибку:
- Формируется нестандартное TLS-расширение с **неверным ID** и **некорректной длиной**
- Из-за этого ClientHello Telegram легко матчится ТСПУ
- Патч подготовлен, но на момент статьи не смерджен в официальный tdesktop
**Этот случай — иллюстрация того, как даже небольшая ошибка в TLS-реализации клиента делает его узнаваемым для DPI.** Применительно к XRay: если клиент (v2rayNG, XRay-core на Android) отправляет ClientHello, который отличается от нормального браузерного, DPI может отфильтровать соединение ещё до того, как XRay сервер успеет проверить REALITY-подпись.
## Как DPI взаимодействует с XRay Reality
### Вариант A — Дроп после ClientHello
```mermaid
sequenceDiagram
Client->>DPI: TCP SYN
DPI->>Server: TCP SYN
Server->>DPI: TCP SYN-ACK
DPI->>Client: TCP SYN-ACK
Client->>DPI: TCP ACK
Client->>DPI: TLS ClientHello
DPI->>DPI: Анализ fingerprint
Note over DPI: ClientHello не похож на браузерный?<br/>Дропаем/инжектим RST
DPI->>Client: RST (поддельный)
```
**Проявление:** `failed to read client hello` в логах сервера, при этом TCP SYN успешно доходит.
### Вариант B — Деградация после установки соединения
DPI пропускает ClientHello, но после установки REALITY-сессии анализирует поведение трафика. Если трафик не похож на HTTPS — начинает дропать пакеты.
**Проявление:** соединение устанавливается, работает несколько секунд/минут, потом обрывается.
### Дополнительные механизмы DPI из статьи
Статья описывает несколько техник DPI, которые выходят за рамки простого fingerprint-матчинга:
1. **Поведенческий анализ после соединения:** DPI может пропустить ClientHello, установить TLS-сессию, но затем анализировать **паттерны трафика** (размеры пакетов, частоту, направление). Если трафик не похож на HTTPS-сёрфинг (например, идёт постоянный поток данных без видимых HTTP-запросов), DPI начинает дропать или деградировать соединение.
2. **Деградация (throttling) вместо блокировки:** Вместо RST или дропа пакетов DPI может **замедлять** соединение — искусственно вносить задержки, ограничивать пропускную способность. Пользователь видит «тормозит, но работает», что сложнее диагностировать, чем полный обрыв.
3. **Адаптивное обучение:** DPI не имеет статической базы fingerprint'ов. Он может **обучаться** новым сигнатурам в реальном времени. Если новый fingerprint появился и DPI его пропустил (например, потому что трафика мало), через некоторое время он может начать его блокировать. **Это объясняет паттерн «работало вчера, перестало сегодня»** — DPI потребовалось время, чтобы накопить статистику и обучить классификатор.
4. **Корреляция по нескольким признакам:** DPI может комбинировать fingerprint + SNI + IP + порт + поведение. Если хотя бы один признак совпадает с известной сигнатурой прокси — соединение помечается как подозрительное.
### Баг в encrypted_client_hello Telegram (из статьи)
В коде генерации `encrypted_client_hello` у Telegram нашли ошибку:
- Формируется нестандартное TLS-расширение с **неверным ID** и **некорректной длиной**
- Из-за этого ClientHello Telegram легко матчится ТСПУ
- Патч подготовлен, но на момент статьи не смерджен в официальный tdesktop
**Этот случай — иллюстрация того, как даже небольшая ошибка в TLS-реализации клиента делает его узнаваемым для DPI.** Применительно к XRay: если клиент (v2rayNG, XRay-core на Android) отправляет ClientHello, который отличается от нормального браузерного, DPI может отфильтровать соединение ещё до того, как XRay сервер успеет проверить REALITY-подпись.
## Меры противодействия
1. **Использовать Reality вместо Fake-TLS/MTProxy** — Reality уже имеет встроенную маскировку под реальный HTTPS
2. **Менять `fingerprint` в клиенте** — `chrome` / `firefox` / `random`. Если провайдер знает fingerprint конкретного браузера, смена маски может помочь
3. **Менять `dest` на сервере** — если DPI блокирует fingerprint клиента для конкретного сайта, смена `reddit.com` на `cloudflare.com` или `microsoft.com` может обойти блокировку (потому что DPI может сверять fingerprint + dest)
4. **Добавлять второй порт** — 8443, 2053, 2096 — на разных портах DPI может работать по-разному
5. **Encrypted Client Hello (ECH)** — скрывает часть параметров TLS-рукопожатия, но пока не везде поддерживается и может блокироваться отдельно
6. **Обновлять клиент** — fingerprint клиента может меняться с версиями v2rayNG/XRay-core
## Эмпирические наблюдения: когда меры не помогают (сессия 2026-07-15)
В ходе диагностики на Ростелеком (домашний WiFi) был задокументирован случай, когда **ни одна из стандартных мер не дала результата**:
| Мера | Что пробовали | Результат |
|------|--------------|-----------|
| Смена порта | 443 → 8443 → 50000 | `failed to read client hello` на всех |
| Смена dest | reddit.com → microsoft.com → discord.com | `failed to read client hello` на всех |
| Смена fingerprint | chrome → random | Без изменений |
| Смена shortId | Не пробовали | — |
**Контекст:** пользователь Ростелеком, домашний WiFi. Вечером предыдущего дня соединение работало. На следующее утро/день — перестало на всех портах и всех маскирующих доменах. Сервер XRay 26.7.11, клиент Xray-core 26.6.27 (встроен в v2rayNG 2.2.6). Параметры: flow=xtls-rprx-vision, fingerprint=chrome (позже random), encryption=none.
**Вывод:** DPI на конкретном провайдере (Ростелеком) может детектить XRay Reality **независимо от порта и маскирующего домена**. Fingerprint клиента (v2rayNG отправляет ClientHello с характерными параметрами XRay-core) является достаточным признаком для блокировки. Это означает, что DPI обучился на fingerprint XRay-core, а не на конкретном сайте или порте.
**Ограничение эксперимента:** Не пробовались другие транспорты (gRPC, WebSocket, QUIC), не пробовался Trojan или Shadowsocks на тех же портах. Возможно, блокировка специфична именно для VLESS+Reality+Vision — следующая попытка должна сменить протокол.
### Что пробовать в такой ситуации (от простого к сложному)
1. **Сменить transport** — Reality → WebSocket + TLS (через nginx reverse proxy) → другая сигнатура ClientHello
2. **Сменить протокол** — VLESS → Trojan → другой fingerprint XRay-core
3. **Сменить `fingerprint` на `random`** в клиенте — тогда XRay-core будет генерировать случайный ClientHello каждый раз, что делает fingerprint-анализ бесполезным
4. **Добавить CDN/Cloudflare перед сервером** — если IP провайдера попал в «серые списки», CDN скроет реальный IP
5. **Try AmneziaWG** — использует другой механизм обфускации, не основанный на TLS fingerprint
6. **Try Shadowsocks + v2ray-plugin (WebSocket)** — другая транспортировка, другой fingerprint
### Ключевой вывод
Статья про MTProxy — это не про MTProxy. Это про то, что **DPI перешёл на новый уровень анализа**. Fingerprint-фильтрация ClientHello стала реальностью. XRay Reality спроектирован с учётом этого (использует настоящий TLS-сервер), но не застрахован полностью: если ClientHello от клиента выглядит подозрительно, DPI может заблокировать его ещё до REALITY-проверки.
**Урок на будущее:** fingerprint клиента XRay-core (даже с `chrome`/`random`) может быть распознан DPI независимо от порта и dest. В такой ситуации нужно менять не параметры Reality, а транспорт/протокол целиком.