← Назад в базу знаний

Маскировка TLS-рукопожатия: обход DPI через прокси с имитацией браузерного fingerprint

Маскировка TLS-рукопожатия: обход DPI через прокси с имитацией браузерного fingerprint

Суть проблемы

Deep Packet Inspection (DPI) давно перестал быть просто анализатором заголовков. Современные системы блокируют не по IP или SNI — они смотрят на то, как именно клиент устанавливает TLS-соединение. Если рукопожатие отличается от эталонного браузерного — соединение режут.

Проблема в том, что стандартные прокси-клиенты (OpenVPN, Shadowsocks, обычный curl) генерируют TLS-рукопожатие с характерными признаками. DPI это видит и отправляет RST-пакет ещё до того, как данные ушли на сервер.

Архитектура TLS-рукопожатия

HTTPS-соединение начинается с ClientHello. В этом пакете лежит:

- версия TLS

- список Cipher Suites

- TLS-расширения (SNI, ALPN, key_share, supported_groups)

- порядок этих расширений

- случайные значения в полях

Браузеры (Chrome 120+, Firefox 121+) отправляют ClientHello с конкретным fingerprint. Например, Chrome использует строго определённый набор Cipher Suites, расширения в фиксированном порядке, конкретные значения в TLS 1.3 key_share.

Если ваш прокси-клиент отправляет ClientHello с другим fingerprint — DPI это видит. И блокирует.

Как DPI детектирует прокси

Типичный сценарий блокировки:

1. Клиент шлёт ClientHello с fingerprint, непохожим на браузерный

2. DPI видит нестандартный набор Cipher Suites (например, отсутствие TLS_CHACHA20_POLY1305_SHA256)

3. DPI замечает порядок расширений, не совпадающий с браузерным (Chrome: supported_versions, key_share, signature_algorithms, psk_key_exchange_modes)

4. Срабатывает блокировка

Пример: OpenVPN поверх TCP на порту 443. DPI видит ClientHello с Cipher Suites, где нет ни одного AEAD-набора. Сразу RST.

Механизм маскировки

Идея простая: прокси-клиент должен эмулировать TLS-рукопожатие конкретного браузера. Полностью. Не только Cipher Suites, но и порядок расширений, значения в key_share, длину random-поля, версию TLS в supported_versions.

Современные инструменты (uTLS, gost, xray-core) позволяют задать fingerprint клиента. Выбираешь chrome или firefox — и прокси генерирует ClientHello, неотличимый от браузерного.

Разбор fingerprint Chrome 120

Chrome 120 отправляет ClientHello с:

- Cipher Suites: 0x1301, 0x1302, 0x1303, 0xC02B, 0xC02F, 0xC02C, 0xC030, 0xCCA9, 0xCCA8, 0xCCAA, 0xC013, 0xC014, 0x009C, 0x009D, 0x002F, 0x0035, 0x000A

- Extensions в порядке: server_name, extended_master_secret, renegotiation_info, supported_groups, ec_point_formats, session_ticket, application_layer_protocol_negotiation, status_request, signed_certificate_timestamp, key_share, supported_versions, psk_key_exchange_modes, compress_certificate, application_settings

- TLS 1.3 supported_versions: 0x0304, 0x0303, 0x0302, 0x0301

- key_share: X25519, P-256

Если ваш прокси отправляет key_share только с P-256 без X25519 — это уже подозрительно. DPI может сбросить соединение.

Реализация на xray-core

xray-core поддерживает fingerprint через VLESS и Trojan. Конфиг выглядит так:

```json

{

"outbounds": [

{

"protocol": "vless",

"settings": {

"vnext": [

{

"address": "server.example.com",

"port": 443,

"users": [

{

"id": "uuid-here",

"encryption": "none",

"flow": "xtls-rprx-vision"

}

]

}

]

},

"streamSettings": {

"network": "tcp",

"security": "tls",

"tlsSettings": {

"serverName": "server.example.com",

"fingerprint": "chrome",

"allowInsecure": false

}

}

}

]

}

```

Параметр `fingerprint: "chrome"` заставляет xray-core генерировать ClientHello, идентичный Chrome 120. DPI видит нормальное браузерное рукопожатие.

Проверка fingerprint

Можно проверить, какой fingerprint отдаёт ваш клиент. Используем tcpdump и wireshark:

```bash

tcpdump -i eth0 -w handshake.pcap host server.example.com and port 443

```

Открываем pcap в Wireshark. Смотрим ClientHello. В поле TLS Handshake -> Cipher Suites должно быть ровно 17 наборов в правильном порядке. Extensions — строго как у Chrome.

Если видите лишние расширения (например, padding) — fingerprint не совпадает. DPI это заметит.

Кейс: блокировка OpenVPN на 443 порту

Проблема: OpenVPN на TCP 443 блокировался через 3-5 пакетов после установки соединения. DPI видел нестандартное TLS-рукопожатие.

Причина: OpenVPN использует свою реализацию TLS, которая не эмулирует браузерный fingerprint. ClientHello содержал только 4 Cipher Suites, порядок расширений был произвольным, key_share отсутствовал.

Решение: замена OpenVPN на xray-core с VLESS+XTLS Vision и fingerprint chrome. После перехода — соединение стабильно держится сутками. DPI не вмешивается.

Кейс: проблемы с MTU при маскировке

Пример: сервер nginx 1.24 с TLS 1.3, клиент через прокси с fingerprint chrome. На некоторых маршрутах соединение рвалось при передаче больших файлов.

Причина: DPI на промежуточном роутере не блокировал соединение, но фрагментировал пакеты. TLS-расширения в ClientHello занимали больше 1500 байт (MTU). Пакет фрагментировался, DPI не мог собрать его обратно и сбрасывал.

Решение: принудительная установка MSS на прокси-клиенте:

```bash

iptables -t mangle -A OUTPUT -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1400

```

После этого ClientHello укладывался в один пакет. Фрагментация прекратилась.

Кейс: fingerprint firefox на старом оборудовании

Проблема: прокси с fingerprint firefox работал на десктопе, но на роутере с OpenWrt (MIPS, 64MB RAM) соединение рвалось каждые 10-15 минут.

Причина: реализация uTLS для firefox использует больше расширений и сложнее в обработке. На слабом железе возникали таймауты при генерации ClientHello. DPI успевал сбросить соединение до отправки полного рукопожатия.

Решение: смена fingerprint на chrome (он легче) и увеличение таймаутов в конфиге xray-core:

```json

{

"streamSettings": {

"sockopt": {

"tcpFastOpen": true,

"tcpKeepAliveInterval": 30,

"tcpKeepAliveIdle": 300

}

}

}

```

Соединение стабилизировалось. Fingerprint chrome на MIPS работал без сбоев.

Сравнение fingerprint браузеров

| Браузер | Количество Cipher Suites | Расширений | Размер ClientHello | Особенности |

|---------|-------------------------|------------|-------------------|-------------|

| Chrome 120 | 17 | 14 | ~512 байт | key_share с X25519 и P-256 |

| Firefox 121 | 22 | 16 | ~600 байт | Добавлен GREASE, больше расширений |

| Safari 17 | 15 | 12 | ~480 байт | Нет compress_certificate |

| Edge 120 | 17 | 14 | ~512 байт | Идентичен Chrome |

Chrome — самый лёгкий для эмуляции. Firefox сложнее, но тоже работает. Safari — редкий гость, DPI может его блокировать из-за малого количества расширений.

Проверка через curl

Можно проверить, как ваш прокси эмулирует fingerprint. Используем curl с ключом --tls13-ciphers:

```bash

curl --tls13-ciphers TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384 \

--tls-max 1.3 \

-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" \

https://example.com

```

Но curl не умеет эмулировать полный fingerprint. Он отправляет свой набор Cipher Suites. Для теста лучше использовать специализированные утилиты.

Мониторинг в реальном времени

Чтобы видеть, что происходит с TLS-рукопожатием, можно использовать tshark:

```bash

tshark -i eth0 -Y "tls.handshake.type == 1" -T fields -e tls.handshake.ciphersuites -e tls.handshake.extensions_server_name

```

Если в выводе видите нестандартные Cipher Suites (например, 0x00FF, 0xC00A) — fingerprint сбит. DPI это заметит.

Ограничения подхода

Маскировка TLS-рукопожатия не решает все проблемы. DPI может анализировать:

- время между пакетами (inter-packet gap)

- размеры последующих пакетов после рукопожатия

- поведение на уровне TCP (window scaling, SACK)

Если после браузерного ClientHello прокси начинает слать пакеты с характерной структурой Shadowsocks или VLESS — DPI это заметит. Маскировка только первого пакета недостаточна.

Итог

Эмуляция браузерного fingerprint в TLS-рукопожатии — рабочий метод обхода DPI. Но это не серебряная пуля. Нужно следить за:

- точным соответствием fingerprint выбранного браузера

- размером ClientHello (должен быть меньше MTU)

- поведением после рукопожатия (не должно отличаться от браузерного)

На практике связка xray-core с fingerprint chrome и корректными настройками MTU даёт стабильный обход DPI в 95% случаев. Остальные 5% — экзотические DPI, которые анализируют не только первый пакет.

✔️Купить прокси