todo/VLESS/dpi-tls-june-2026.md
loop-uh 737f065567 Вики переехала на wiki2.zapret.moe: домен заменён во всём хранилище
wiki.zapret.moe заблокирован в России, читатели до редиректа не доходят. Во всех заметках, плашках [!mirror], ссылках и скриптах домен заменён на wiki2.zapret.moe; в AGENTS.md записано правило — ссылаться только на wiki2. Скрипт статистики считает своими заходы с обоих доменов. Чужие незакоммиченные правки в nuc/ в коммит не попали — только замена домена.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 15:15:27 -04:00

684 lines
91 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.

---
date: 2026-06-07
tags:
- dpi
- vless
- reality
- tls
- utls
- mux
- rkn
link: https://habr.com/ru/articles/1044396/
aliases:
- Схема ограничений июнь 2026
- DPI TLS heuristics 2026
img:
description: "Как DPI «замораживает» VLESS+REALITY в июне 2026: три сигнала — подсеть хостинга, TLS-фингерпринт, частота соединений — и как разорвать цепочку."
---
> [!mirror] Резервное зеркало
> Актуальная версия этой страницы — на основной вики: [wiki2.zapret.moe/VLESS/dpi-tls-june-2026](https://wiki2.zapret.moe/VLESS/dpi-tls-june-2026)
# 🧊 Как DPI «замораживает» VLESS+REALITY: разбор схемы ограничений (июнь 2026)
> [!quote] Первоисточник
> Этот разбор основан на статье **Петра Осетрова** (@hyperion_cs) на Хабре:
> 👉 **[«О схеме ограничений РКН в июне 2026-го» — habr.com/ru/articles/1044396](https://habr.com/ru/articles/1044396/)**
>
> Все числовые параметры (пороги, тайминги, списки фингерпринтов) взяты из этой статьи. Ниже — простое объяснение «на пальцах» плюс расширенные технические детали по uTLS и mux от себя.
> [!info] Дисклеймер
> Материал носит **исследовательский и образовательный** характер. Задача — понять, *по каким признакам* современный DPI отличает обходные средства от обычного трафика, и почему одной волшебной галочкой проблему больше не решить.
> [!warning] Важно про статус этих данных
> Описанная схема — это **результат реверс-инжиниринга**: автор сам называет её «Siberian» и добавил одноимённый чекер в dpi-checkers. Это наблюдения **одного исследователя**; сам автор оговаривает, что **параметры метода различаются от оператора к оператору и меняются со временем**.
>
> Параллельно, в тот же период, задокументированы и **другие** механизмы блокировки — заморозка соединения после ~16 КБ / ~25 пакетов (метод «tcp 16-20»), CIDR-whitelist по подсетям назначения, SNI-whitelist (см. [net4people/bbs #490](https://github.com/net4people/bbs/issues/490)). Поэтому всё ниже — **снимок одной наблюдаемой волны на июнь 2026**, а не универсальный закон. Конкретные числа читайте как «по наблюдениям автора», а не как точные константы системы.
---
## TL;DR — если совсем коротко
Летом 2026 года перестала надёжно работать связка [[xray/project-x|xray]] + **VLESS + REALITY**.
Важно: REALITY **не взломали**. Его шифрование по-прежнему неотличимо от настоящего TLS. Сломалось другое: DPI перестал заглядывать *внутрь* пакета (это бесполезно) и начал смотреть на **поведение** соединения снаружи.
Блокировка включается, только когда **совпали сразу три признака** (это важно — именно «И», а не «ИЛИ»). Нарушьте любой один — и правило на вас не сработает.
---
## Объясняю на пальцах: что вообще произошло
Представьте таможню на границе (это наш DPI).
Раньше таможенник открывал каждый чемодан и смотрел, что внутри. REALITY — это чемодан с идеальной маскировкой: снаружи и внутри он выглядит как чемодан обычного туриста, едущего на `www.microsoft.com`. Подделку не видно, потому что для этого нужен секретный ключ, которого у таможни нет. Поэтому годами всё работало: «внутри чисто — проходи».
Теперь таможенник **перестал открывать чемоданы** (всё равно бесполезно) и начал смотреть на **поведение пассажира**:
- **Откуда приехал?** — если из района, где живут одни «контрабандисты» (популярные хостинги), это подозрительно.
- **Как выглядит?** — если одет в форму, в которой обычно ходят нарушители (фингерпринт Chrome), это подозрительно.
- **Как себя ведёт?** — если бегает туда-сюда через границу 10 раз в минуту (лавина соединений), это подозрительно.
И только когда **все три** совпали — пассажира «тормозят». Криптография тут уже ни при чём: ловят не *содержимое*, а *манеру*.
---
## Алгоритм блокировки: три сигнала и один триггер
Цензор оценивает **`ClientHello`** — самый первый пакет TLS-рукопожатия — у **каждого** TLS-соединения. Среди прочего он смотрит на такие атрибуты:
> [!quote] Что оценивает цензор (из первоисточника)
> - **IP-адрес сервера** (точнее — его *подсеть*);
> - **SNI** (Server Name Indication — то самое замаскированное имя);
> - **фингерпринт «браузера»** (точнее — того, под кого мимикрируют; у REALITY это делает uTLS).
К этим статическим атрибутам добавляется ещё и **поведение** — частота и параллелизм соединений. «Заморозка» включается, **только когда совпали сразу несколько признаков** (логическое «И»): подозрительная подсеть + подозрительный фингерпринт + аномальная частота к одному SNI. Разберём их по очереди.
> [!note] Почему сигналов «три», хотя атрибутов перечислено больше
> SNI в списке выше — **не отдельный сигнал**, а *ключ агрегации* для поведенческого Сигнала 3: частота соединений считается раздельно по каждому SNI. Поэтому ключевых триггеров остаётся три — **подсеть**, **фингерпринт** и **частота к одному SNI**.
### Сигнал 1. Подсеть сервера — «откуда» вы подключаетесь
DPI смотрит на IP-адрес вашего сервера и проверяет, не входит ли он в список «подозрительных» подсетей. В этот список массово попали диапазоны популярных хостингов, в том числе **российских**:
- **Selectel**
- **Яндекс.Облако**
Логика простая: именно там дешевле и проще всего поднять свой узел, поэтому там их больше всего.
Важный нюанс: схема завязана **не на конкретные IP** отдельных узлов, а на **целые подсети и даже автономные системы (AS)**.
> [!quote] Из первоисточника
> Схема не завязана напрямую на конкретные IP промежуточных узлов (напр., ваших серверов). Это, в общем-то, неплохо — значит, узлы не улетели в некий чёрный список (особенно в свете того, что некоторые приложения «стучат»). Плохая новость в том, что затронуты целые подсети и даже AS, в т.ч. популярных российских дата-центров (Selectel, Яндекс.Облако и др.). Это заметно отличается от прежних методов, которые задевали только зарубежных провайдеров (tcp 16-20, aka l4-25, и пр.).
Что это значит на практике: ваш конкретный IP в чёрный список **не попадает** (его не «сожгли») — под подозрением сразу весь диапазон хостинга. Хорошая сторона — сменить IP в пределах того же провайдера не поможет, но и «гореть» вашему адресу не за что. Плохая — отсюда же берётся сопутствующий ущерб для легальных соседей по подсети (см. раздел про обычный Chrome ниже).
> [!tip] Что это значит для вас
> Сервер в «народном» дата-центре — первый красный флаг. Чем менее предсказуемы провайдер и подсеть, тем лучше. Практику выбора см. в [[VPS/VPS|VPS]].
### Сигнал 2. TLS-фингерпринт клиента — «чем» вы подключаетесь
Когда ваша программа начинает TLS-соединение, она первым делом отправляет пакет **`ClientHello`**. В нём — список поддерживаемых шифров, расширений, их порядок и прочие технические мелочи. Этот набор у каждой реализации TLS свой, как почерк. По нему можно понять, **какая именно программа** сгенерировала пакет (подробнее — в разделе про uTLS ниже).
#### Как выглядит этот «почерк» на самом деле
Возьмём эталонный `ClientHello` из [RFC 8448](https://www.rfc-editor.org/rfc/rfc8448) — это пример прямо из стандарта, поэтому каждый байт можно сверить.
**1. Текстовая форма** — то, как пакет разбирает Wireshark/`tshark` (дерево полей):
```text
TLSv1.3 Record Layer: Handshake Protocol: Client Hello
Content Type: Handshake (22) # 0x16
Version: TLS 1.0 (0x0301) # версия RECORD-слоя (легаси, для совместимости)
Length: 196
Handshake Protocol: Client Hello
Handshake Type: Client Hello (1)
Length: 192
Version: TLS 1.2 (0x0303) # legacy_version — НЕ настоящая версия (см. ниже)
Random: cb34ecb1 e78163ba 1c38c6da … # 32 байта
Session ID Length: 0
Cipher Suites Length: 6
Cipher Suites (3):
TLS_AES_128_GCM_SHA256 (0x1301)
TLS_CHACHA20_POLY1305_SHA256 (0x1303)
TLS_AES_256_GCM_SHA384 (0x1302)
Compression Methods: null (0)
Extensions Length: 145
Extension: server_name → "server" # SNI
Extension: renegotiation_info
Extension: supported_groups → x25519, secp256r1, secp384r1, …
Extension: session_ticket
Extension: key_share → x25519 (32-байтный публичный ключ)
Extension: supported_versions → TLS 1.3 (0x0304) # ← НАСТОЯЩАЯ версия
Extension: signature_algorithms → ecdsa_secp256r1_sha256, …
Extension: psk_key_exchange_modes
Extension: record_size_limit
```
**2. Байтовая форма** — тот же пакет «на проводе» (hex с аннотациями):
```text
16 03 01 00 c4 TLS-запись: Handshake, ver 0x0301, длина 196
01 00 00 c0 ClientHello, длина 192
03 03 legacy_version = 0x0303 (TLS 1.2)
cb 34 ec b1 e7 81 63 ba 1c 38 c6 da cb 19 ┐
6a 6d ff a2 1a 8d 99 12 ec 18 a2 ef 62 83 │ Random (32 байта)
02 4d ec e7 ┘
00 Session ID length = 0
00 06 13 01 13 03 13 02 Cipher Suites (6 б): 1301 1303 1302
01 00 Compression: 1 метод = null
00 91 Extensions, длина = 145 байт
00 00 00 0b 00 09 00 00 06 73 65 72 76 65 72 server_name → "server"
ff 01 00 01 00 renegotiation_info
00 0a 00 14 00 12 00 1d 00 17 00 18 00 19 … supported_groups
00 23 00 00 session_ticket
00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 … key_share (x25519)
00 2b 00 03 02 03 04 supported_versions → 0x0304 (TLS 1.3)
00 0d 00 20 00 1e 04 03 05 03 … signature_algorithms
00 2d 00 02 01 01 psk_key_exchange_modes
00 1c 00 02 40 01 record_size_limit
```
Фингерпринт — это **набор и порядок** вот этих cipher suites и extensions. Заметьте: `73 65 72 76 65 72` в hex — это ASCII-строка `server` (тот самый SNI, видный **открытым текстом**). Реальный Chrome выглядел бы иначе: GREASE-значения, расширения `ALPN` и `ECH`, post-quantum `key_share` (`X25519MLKEM768`), другой порядок полей. Именно этот «слепок» и сворачивают в JA3/JA4 (см. раздел про uTLS), по нему DPI и опознаёт, кто перед ним.
> [!note] Мелкий, но важный нюанс про версию
> Обратите внимание: в поле версии стоит `0x0303` (TLS 1.2), хотя это TLS 1.3. Так сделано **нарочно** — ради совместимости со старыми серверами. Настоящую версию несёт расширение `supported_versions` (`0x0304`). Поэтому JA4 берёт версию TLS именно оттуда, а не из легаси-поля.
И вот ловушка: xray умеет притворяться чужим почерком, и по умолчанию **почти все ставили Chrome** — он самый популярный, прятаться логичнее в толпе. В итоге сочетание «почерк Chrome + признаки прокси» само стало маркером.
| 🚩 Подозрительные фингерпринты | ✅ «Лояльные» фингерпринты |
| --- | --- |
| Chrome | Firefox |
| Safari | Edge |
| iOS | Android OkHttp |
| | 360 Browser |
| | QQ Browser |
> [!warning] Парадокс
> Самый популярный браузер планеты оказался самым «палевным» — именно потому, что под него массово маскируются. Безопаснее то, под что маскируются реже.
### Сигнал 3. Частота и параллелизм — «как» вы подключаетесь
Третий признак — поведенческий, и именно он чаще всего вас и выдаёт. Точная формулировка триггера из первоисточника:
> **более 3 параллельных попыток установить TLS-соединение, с задержкой между ними менее ~350-400 мс, за последние 60 секунд** — к одному и тому же SNI.
> [!warning] По этому порогу гуляют устаревшие цифры
> Первоисточник правился трижды и без пометок: 6 июня 2026 там стояло «~100 мс», 7 июня — «~20-50 мс», и лишь 9 июня появилось нынешнее «~350-400 мс», которое держится с тех пор. Промежуточный вариант успел разойтись по перепечаткам и попал в англоязычный пересказ в [обсуждении Xray-core #6293](https://github.com/XTLS/Xray-core/issues/6293), снятый за сутки до правки. Если встретите «20-50 мс» — это старый срез. Актуальное значение подтверждается и свежим [предложением #6547](https://github.com/XTLS/Xray-core/issues/6547) от 27 июля 2026, где параметр `hMinSocketInterval` предлагают выставлять в 400–600 мс именно с запасом над этим порогом.
Разберём по словам:
- **более 3 соединений** — то есть 4 и больше;
- **задержка между ними < ~350-400 мс** — то есть они идут залпом, почти одновременно;
- **за последние 60 секунд** — окно, в котором DPI это считает;
- **к одному SNI** — все на одно и то же замаскированное имя (например, `www.microsoft.com`).
Откуда берётся такой залп? Это типичный почерк прокси. Вы открываете браузер, в нём десяток вкладок — и каждая инициирует своё соединение. Все они мультиплексируются на **один** замаскированный SNI. Живой человек, реально открывший `www.microsoft.com`, так себя не ведёт — он не создаёт 10 одновременных коннектов на этот домен.
> [!tip] Что это значит для вас
> Лавина одновременных соединений на один SNI — поведенческая аномалия. Лечится мультиплексированием (`mux`) и распределением по разным SNI (см. раздел про mux ниже).
### Что происходит при срабатывании
Когда совпали **все три** условия, трафик к узлу **«замораживается» на 120 секунд**. Важная деталь: соединения не рвутся демонстративно (это было бы слишком явной цензурой) — они тихо деградируют. Растут таймауты, падает скорость, всё «как будто само тормозит». Внешне похоже на плохой интернет, а не на блокировку.
![[wiki-anim-dpi-tls-gates.svg|Схема: правило ТСПУ срабатывает, только если выполнены все три условия]]
---
## Почему обычный Chrome работает, хотя «лояльным» его не назвали
Здесь возникает резонный вопрос: если фингерпринт Chrome — «подозрительный», почему миллионы людей спокойно сидят в обычном Chrome и ничего не тормозит? А заодно — почему при этом у части людей вдруг **ломаются некоторые российские сайты**?
Ответ — снова в логике **«И трёх условий»**. Вспомните: чтобы поймать заморозку, нужны **все три** сигнала одновременно. У обычного веб-сёрфинга почти всегда не выполняется **первый** — про подсеть.
**Почему Chrome обычно работает.** Когда вы просто листаете интернет, вы ходите на реальные сервисы — Google, YouTube, банки, маркетплейсы. Они живут на собственной инфраструктуре и больших CDN, которые в список «подозрительных подсетей» не входят (а часто и вовсе в [[Белые списки|белых списках]]). Получается:
- 🚩 Фингерпринт Chrome — да, *подозрительный* (Сигнал 2 ✅);
- лавина параллельных соединений — да, браузер их открывает (Сигнал 3 может сработать);
- **но подсеть назначения — чистая** (Сигнал 1 ❌).
Одно звено цепи разорвано → правило **не срабатывает**. Именно поэтому Chrome для обычного веба «прозрачен»: его спасает не фингерпринт, а **адрес назначения**. А вот ваш личный VLESS-сервер на Selectel/Яндекс.Облаке этот первый сигнал как раз включает — отсюда и разница.
**Почему всё-таки ломаются некоторые ру-сайты.** Это оборотная сторона грубой эвристики «по подсети». В списки подозрительных попали диапазоны **российских** хостингов (Selectel, Яндекс.Облако), а на этих же хостингах живёт масса **легальных** сайтов и сервисов — тех, кто просто арендует там сервер. DPI не умеет отличить «прокси на Selectel» от «интернет-магазина на Selectel» — для него это одна подсеть.
И если вы в обычном Chrome заходите на такой легальный сайт, расположенный на «помеченном» хостинге, может совпасть всё три:
- сайт на подозрительной подсети (Сигнал 1 ✅);
- вы в Chrome (Сигнал 2 ✅);
- браузер открыл несколько быстрых параллельных соединений к его домену (Сигнал 3 ✅).
→ Получаем **ложное срабатывание**: легальный сайт начинает тормозить, хотя никто ничего не обходил. Это и есть «сопутствующий ущерб» (collateral damage) схемы: блокировка по подсети неизбежно задевает добросовестных соседей по хостингу.
> [!summary] Коротко
> Обычный Chrome спасает **чистая подсеть назначения**, а не сам браузер. Где подсеть «грязная» (ваш VPS или легальный сайт на том же хостинге) — там при Chrome и залпе соединений ловят всех подряд, включая невиновных.
---
## Интересный нюанс: ловушка для тех, кто «дёргается»
Самая хитрая часть схемы — реакция на попытку быстро поменять настройки.
Допустим, вас «заморозили». Вы решаете: «наверное, дело в фингерпринте» — и тут же переключаете Chrome на Firefox, переподключаясь. Логично же? Но для DPI это **отдельный сигнал**: только что соединение получило деградацию — и человек моментально сменил TLS-почерк. Так ведёт себя именно тот, кто *осознанно обходит* ограничение.
В ответ прилетает **расширенная блокировка на 600 секунд** — и уже **на все** TLS-соединения к этому узлу. Важно: на эти 10 минут замораживается **любой** TLS, **независимо и от фингерпринта, и от SNI** — сменить почерк или замаскированное имя уже не поможет. Сам TCP-коннект при этом проходит (рукопожатие на уровне TCP устанавливается), душится именно TLS поверх него.
> [!danger] Мораль
> Система ловит не только сам обход, но и **паттерн адаптации**. Нервно крутить настройки под нагрузкой — делать себе хуже. Правильная стратегия: не реагировать рефлекторно, а **изначально** не попадать в цепочку.
---
## 🔬 Технические детали: uTLS — как работает TLS-почерк
Раздел для тех, кто хочет понять механику, а не просто поставить галочку.
### Что такое JA3/JA4 и почему по TLS видно программу
`ClientHello` — это первый, ещё **не зашифрованный** пакет TLS-рукопожатия. В нём открытым текстом передаются:
- версия TLS;
- список **cipher suites** (наборов шифров) — и **в каком порядке**;
- список **extensions** (расширений: SNI, ALPN, supported_groups, signature_algorithms, key_share и т.д.) — и **в каком порядке**;
- эллиптические кривые, форматы точек, GREASE-значения и пр.
Конкретная программа (Chrome, Firefox, Go-приложение, curl) собирает этот набор по-своему: свой порядок шифров, свой набор расширений. Если взять все эти поля и прогнать через хеш, получится **отпечаток**. По нему DPI с высокой точностью говорит: «это Chrome 124» или «это Go-клиент».
Два основных формата отпечатков:
- **JA3** (старый) — это MD5-хеш от полей `ClientHello`, **взятых в том порядке, в каком они идут в пакете**. Минус: Chrome специально **тасует порядок расширений** от соединения к соединению, поэтому JA3-хеш у него «плавает» и легко обходится.
- **JA4** (новый, более устойчивый) — как раз поэтому он **сортирует** шифры и расширения перед хешированием и **игнорирует GREASE**. Это не один хеш, а строка из трёх частей через `_` (`a_b_c`):
- **a** (читаемая): протокол (`t` — TLS-over-TCP, `q` — QUIC, `d` — DTLS), версия TLS, есть ли SNI (`d` = domain / `i` = IP), число шифров, число расширений и ALPN (первый и последний символ значения первого ALPN, напр. `h2`);
- **b**: усечённый SHA256 от **отсортированных** cipher suites;
- **c**: усечённый SHA256 от **отсортированных** extensions (без SNI и ALPN), за которыми идут **signature algorithms — уже без сортировки**.
За счёт сортировки шифров и расширений JA4 не «обманывается» их перетасовкой; при этом signature algorithms намеренно оставлены несортированными как дополнительный различающий признак.
Вот в чём беда TLS-обхода на Go: стандартная библиотека `crypto/tls` имеет **очень узнаваемый фингерпринт** — это прямо признают сами разработчики uTLS («Golang's ClientHello has a very unique fingerprint»). В реальном вебе такой почерк почти не встречается → мгновенный маркер прокси. Поэтому **обычный** VLESS/Trojan поверх TLS, если не указать `fingerprint`, спалится сразу.
#### Контраст «почерков»: голый Go `crypto/tls` vs Chrome
Чтобы было видно, *насколько* они различаются — ключевые отличия в `ClientHello` (структурно; точные байты зависят от версии):
| Признак | 🦫 Голый Go `crypto/tls` | 🌐 Chrome 131+ |
| --- | --- | --- |
| **GREASE** | нет нигде | в 5 местах: первый шифр, первое и последнее расширение, `supported_versions`, `supported_groups`, `key_share` |
| **Порядок расширений** | жёстко фиксирован | тасуется на каждом соединении (с Chrome 110, янв. 2023) |
| **`application_settings`** (ALPS) | нет | есть |
| **`compress_certificate`** (brotli) | нет | есть |
| **ECH** (`encrypted_client_hello`) | нет (по умолчанию) | есть (GREASE-ECH или настоящий) |
| **Число расширений** | ~10–12 | ~17–18 |
| **Cipher list** | 13 шифров, сразу с TLS 1.3 AEAD | начинается с GREASE, характерная браузерная раскладка |
Любого из верхних трёх отличий (нет GREASE, фиксированный порядок, нет ALPS/brotli/ECH) уже достаточно, чтобы пассивно отличить Go-клиент от Chrome. Поэтому «голый» Go без uTLS — мгновенный маркер. (Нюанс актуальности: post-quantum `key_share` `X25519MLKEM768` Chrome шлёт с v131, а Go — только с 1.24; на старых версиях Go отсутствие PQ было ещё одним отличием.)
> [!important] Важный нюанс про REALITY
> В REALITY uTLS **встроен и обязателен**: поле `fingerprint` помечено как Required, а режим отключения uTLS (`unsafe`) официально не поддерживается — REALITY использует эту библиотеку для манипуляции низкоуровневыми параметрами TLS. Поэтому «голый» `crypto/tls`-почерк от REALITY **никогда не уходит** — он всегда отправляет валидный фингерпринт браузера. Проблема REALITY в июне 2026 — не в Go-почерке, а в том, что почерк хоть и корректный, но **слишком массовый** (`chrome`). Об этом — ниже.
### Что делает uTLS
[uTLS](https://github.com/refraction-networking/utls) (`refraction-networking/utls`) — это форк стандартного `crypto/tls`, который позволяет **подменить** содержимое `ClientHello`: порядок шифров, набор расширений, GREASE — по готовому шаблону настоящего браузера. То есть xray генерирует `ClientHello`, **неотличимый** от Chrome или Firefox, и JA3/JA4-хеш совпадает с настоящим браузером. (Технически uTLS работает на уровне готовых пресетов-спецификаций; полный побайтовый контроль возможен, но в обычном режиме хватает пресета, чтобы хеши совпали.)
В конфиге xray это поле `fingerprint` внутри `realitySettings`. Кстати, поле с публичным ключом сервера в актуальных версиях xray-core называется `password` (раньше — `publicKey`; старое имя пока работает для совместимости). uTLS поддерживает пресеты вроде `HelloChrome_Auto`, `HelloFirefox_Auto`, `HelloEdge_Auto`, `HelloSafari_Auto`, `HelloRandomized` и др. В xray они задаются короткими именами: `chrome`, `firefox`, `edge`, `safari`, `ios`, `android`, `360`, `qq`, `random`, `randomized`. То есть рекомендованные в таблице выше «лояльные» 360 Browser и QQ Browser пишутся как `"fingerprint": "360"` и `"fingerprint": "qq"`.
```json
"realitySettings": {
"fingerprint": "firefox",
"serverName": "www.microsoft.com",
"password": "<публичный ключ сервера>",
"shortId": "<short id>"
}
```
### Почему это перестало спасать само по себе
uTLS делает почерк **корректным**, но не делает его **редким**. Если все массово ставят `chrome`, то «JA3 Chrome + поведение прокси» становится статистически заметным. DPI не говорит «фингерпринт поддельный» (он валидный!) — он говорит «слишком много именно такого фингерпринта летит на этот странный сервер залпами». Поэтому в июне 2026 совет сместился: брать **не самый массовый** профиль — `firefox`/`edge` и пр.
> [!note] Про `random` и `randomized` — это РАЗНЫЕ режимы
> Их легко перепутать, но ведут себя они по-разному:
> - **`random`** — xray случайно берёт один из готовых **реальных** пресетов браузера (Chrome 131, Firefox 148 и т.п.). Почерк всегда валидный — это безопасный вариант.
> - **`randomized`** (и `randomizednoalpn`) — **синтетическая** генерация: расширения и шифры добавляются/тасуются случайно. Может получиться комбинация, **которой не существует ни у одного реального браузера** — а это само по себе аномалия.
>
> Вывод: бездумно ставить `randomized` не стоит. Лучше явный «лояльный» пресет (`firefox`/`edge`) или, на худой конец, `random` — но не синтетическую рулетку.
### uTLS не маскирует тайминги
Ключевой момент: uTLS правит только **содержимое** `ClientHello`. Он **никак не влияет** на *Сигнал 3* — на то, сколько соединений и с какой частотой вы открываете. Почерк может быть идеальным, но если вы шлёте на один SNI залп коннектов с интервалом между ними менее ~350-400 мс — вас всё равно поймают по поведению. Вот почему одного uTLS мало, и нужен mux.
---
## 🔬 Технические детали: mux — как сгладить лавину соединений
`mux` (мультиплексирование) — это прямое лекарство от *Сигнала 3*.
### Проблема, которую он решает
Без mux каждая вкладка / каждое приложение = **отдельное физическое TCP+TLS-соединение** до сервера. Открыли почту, мессенджер, пару сайтов — и вот уже залп одновременных коннектов на один замаскированный SNI. Ровно тот паттерн, который ловит DPI.
### Как работает mux в xray
Мультиплексирование загоняет **много логических потоков внутрь одного физического соединения**. Снаружи DPI видит **одно** TLS-соединение, по которому идёт постоянный поток данных, — как у обычного пользователя, открывшего тяжёлый сайт. Залпа новых рукопожатий нет → *Сигнал 3* не срабатывает.
```json
"mux": {
"enabled": true,
"concurrency": 8,
"xudpConcurrency": 16,
"xudpProxyUDP443": "reject"
}
```
Разберём параметры:
- **`concurrency`** — сколько логических потоков пускать в одно физическое соединение (для TCP). Допустимый диапазон — `1…128`, по умолчанию `8`. Когда лимит исчерпан, открывается новое физическое соединение. Любое отрицательное значение (`-1`) отключает mux для TCP.
- **`xudpConcurrency`** — то же самое, но для UDP-трафика поверх механизма XUDP (нужно для игр, звонков, QUIC). Диапазон у него **другой** — `1…1024` (а не 1…128, как у TCP); при `0` или отсутствии XUDP-трафик идёт по тому же пути, что и обычный TCP.
- **`xudpProxyUDP443`** — что делать с UDP на 443-м порту (это QUIC/HTTP3). Часто ставят `reject`, чтобы QUIC падал обратно на TCP — так трафик идёт по нашему замаскированному каналу, а не утекает мимо.
> [!warning] У mux есть и обратная сторона
> - **Head-of-line blocking**: все логические потоки делят одно TCP-соединение. Потеря одного пакета тормозит сразу все потоки внутри. На нестабильном канале это ощутимо бьёт по скорости.
> - **Слишком большой `concurrency`** склеивает весь трафик в один долгоживущий коннект — тоже своего рода аномалия (реальные браузеры всё же открывают несколько соединений). Истина посередине: умеренные значения вроде `4–8`.
> - Для **скоростных загрузок** mux иногда наоборот мешает — один коннект упирается в лимиты. Поэтому его часто включают выборочно.
> [!danger] mux и XTLS Vision: TCP-mux не применяется
> Это важно именно для нашей связки. Сейчас стандартный поток для VLESS+REALITY — **XTLS Vision** (`"flow": "xtls-rprx-vision"`). Vision работает на «сыром» (raw) TCP-соединении со `splice`-копированием в ядре Linux, поэтому **TCP-mux при Vision штатно не применяется** — это поведение самого Xray-core, а не сбой (в формулировке ядра: «MUX is not compatible with XTLS raw connections»).
>
> На практике клиенты при Vision генерируют такой блок: `"enabled": true`, `"concurrency": -1` (TCP-mux выключен), но `"xudpConcurrency"` оставлен — чтобы мультиплексировать хотя бы UDP/XUDP. Учтите: при `"enabled": false` XUDP-mux тоже не активируется.
>
> Вывод: не копируйте `"concurrency": 8` бездумно поверх Vision-конфига. Если у вас Vision, бороться с *Сигналом 3* придётся другими средствами — в первую очередь разнесением по разным SNI и сдержанным паттерном соединений.
### Дополнительно: разносите SNI
Триггер *Сигнала 3* считается **на один SNI**. Если раскидать трафик по нескольким разным SNI (см. большой список в [[Zapret/vless-sni|vless-sni]]), нагрузка не концентрируется на одном имени, и порог «>3 соединений с интервалом <~350-400 мс за 60 с» на каждое отдельное имя достигается труднее. mux + несколько SNI вместе очень эффективно сглаживают поведенческий след.
---
## ✅ Что делать: рвём цепочку (по шагам)
Поскольку триггер — это «И» трёх условий, для безопасности достаточно стабильно нарушать **хотя бы одно** звено. На практике стоит закрыть несколько — для запаса прочности.
### Шаг 1. Сменить фингерпринт на «лояльный»
Самое дешёвое действие. В `realitySettings` поменять `fingerprint` с `chrome` на `firefox` или `edge`:
```json
"realitySettings": {
"fingerprint": "firefox"
}
```
### Шаг 2. Включить `mux` и снизить параллелизм
Сглаживаем залп соединений:
```json
"mux": {
"enabled": true,
"concurrency": 8
}
```
И дополнительно — **разнести трафик по нескольким SNI** ([[Zapret/vless-sni|список SNI]]).
> [!warning] Если у вас XTLS Vision
> При стандартном для REALITY flow `xtls-rprx-vision` TCP-mux **не применяется** (см. раздел про mux и Vision выше), так что `concurrency: 8` тут не сработает. Тогда против Сигнала 3 работают только **разные SNI + сдержанный паттерн**, либо переход на **XHTTP+XMUX** (см. FAQ «Можно ли вылечить обе болезни сразу?»).
### Шаг 3. Увести сервер в «невидимую» подсеть
Уходим из массовых диапазонов народных хостингов (Selectel, Яндекс.Облако и т.п.). Менее предсказуемый провайдер/подсеть → выпадаем из списка «подозрительных». Подбор — в [[VPS/VPS|VPS]].
### Шаг 4. Не дёргаться под нагрузкой
Поймали деградацию — **не меняйте фингерпринт на лету**. Лучше переждать окно (120 с) или сменить узел целиком. Оговорка по актуальности: длинную десятиминутную блокировку автор наблюдений в обновлении от 16 июня 2026 отметил как, судя по всему, убранную — но осторожность здесь всё равно дешевле эксперимента.
> [!note] «Смени фингерпринт» — не единственный и не универсальный рецепт
> Совет про `firefox`/`edge` — снимок одной волны, и он не гарантирован. Что важно держать в голове:
> - **Свежесть пресета uTLS важнее выбора браузера.** К концу 2025 — началу 2026 более половины «человеческих» браузерных соединений (по данным Cloudflare Radar) несут **post-quantum** key_share (`X25519MLKEM768`) — он стал дефолтом в Chrome 131 (ноя 2024) и Firefox 132 (окт 2024). Пресет без него, выдающий себя за свежий браузер, уже сам по себе аномален — следите, чтобы uTLS/xray были свежими.
> - **Не путайте с обходами ДРУГИХ блокировок.** Советы «пустой SNI» и «нестандартный порт (47000+)» относятся к более ранней *сигнатурной* блокировке на порту 443 (нач. 2025) и к ограничению по числу TLS-соединений — «сибирскую» схему (подсеть + фингерпринт + частота) они логически не нарушают. `XHTTP` помогает лишь как способ снизить число соединений (это уже делает `mux`), а Shadowsocks-2022 — не обход, а смена протокола (у него нет ни SNI, ни uTLS-почерка браузера). Столкнулись именно с этой схемой — работает только нарушение её трёх условий.
### Проверить себя: dpi-checkers
Автор первоисточника ведёт инструмент **[dpi-checkers](https://github.com/hyperion-cs/dpi-checkers)** (на момент разбора — версия **v0.7.0**). Он прогоняет вашу инфраструктуру по описанным критериям: попадает ли подсеть в подозрительные, как выглядит фингерпринт, ловится ли поведенческий паттерн. Проверки задаются в YAML, например фильтр по организации хостинга:
```yaml
checkers:
webhost:
infra:
- name: Selectel
filter: org("selectel")
```
---
## ❓ Слабые места и частые вопросы
Несколько вопросов, которые закономерно возникают после прочтения.
### Фиксированный список фингерпринтов uTLS — это слабое место?
**Да.** `firefox`, который у вас «снова заработал», — это **снимок конкретной версии** (например `HelloFirefox_120`). И его тоже могут начать ловить. Почему список — структурная слабость:
- **Устаревание.** Пресет заморожен во времени, а живой браузер обновляется каждые недели. `HelloChrome_120` со временем становится *редкой старой* версией на фоне Chrome 13x — особенно теперь, когда у свежих браузеров появился post-quantum `key_share`, которого у старого пресета нет.
- **Перечислимость.** Список открытый и небольшой (~50 пресетов в `u_common.go`). Цензор может просто выписать все JA3/JA4 пресетов uTLS и сверять с распределением реальных браузеров.
- **Несовершенство «попугая».** Даже совпав по версии, uTLS иногда отличается в деталях — вплоть до уязвимостей с CVE: например рассогласование GREASE/ECH-шифров в Chrome-пресете давало комбинацию, невозможную у настоящего Chrome (CVE-2026-27017, закрыто в uTLS 1.8.1).
**Что вас пока спасает:** заблокировать *популярный валидный* фингерпринт целиком цензору дорого — сломаются реальные пользователи Firefox/Chrome. Слабость возникает, когда отпечаток **одновременно** коррелирует с прокси **и** достаточно редкий, чтобы блок был «дешёвым».
### Можно отсканировать свой реальный браузер и залить отпечаток в uTLS-клиент?
И да, и нет — важно разделить **библиотеку** и **конечный клиент**:
- **В библиотеке uTLS — можно.** `Fingerprinter.FingerprintClientHello(rawBytes)` берёт **сырые байты** реального `ClientHello` (захваченные Wireshark'ом — *не* JA3-хеш, он «лоссовый»), строит `ClientHelloSpec`, применяемый через `HelloCustom`.
- **В xray-core и sing-box — НЕЛЬЗЯ.** Оба ограничены меню пресетов; подсунуть свой захваченный `ClientHello` в конфиг нельзя. Это просили напрямую — [xray-core issue #1782](https://github.com/XTLS/Xray-core/issues/1782) **закрыт как «not planned»**.
- **Сканеры своего браузера живы:** [browserleaks.com/tls](https://browserleaks.com/tls) (самый подробный), [tls.peet.ws](https://tls.peet.ws/) (JSON-API). Но они выдают хеши/сводку, **а не raw-байты**, нужные `Fingerprinter`.
Итого: **готового пайплайна для обычного пользователя нет** — это ручная работа разработчика (pcap → `FingerprintClientHello` → свой Go-код). В стандартном клиенте доступны только пресеты + `random`/`randomized`.
> [!warning] Парадокс уникальности
> Если зальёте *свой уникальный* отпечаток — он станет маркером именно **вас**. Сила браузерного фингерпринта в том, что он *массовый*; уникальный — наоборот, деанонимизирует.
### Альтернатива uTLS-пресетам: реальный стек Chromium (naive/cronet)
Раз uTLS — это **попугай** (заморожённый пресет, который перечислим и со временем протухает, а ручной скан своего браузера в стандартный клиент не залить), напрашивается другой путь: не *имитировать* браузер, а **взять настоящий сетевой стек браузера**. Тогда JA3/JA4 — не копия, а подлинник, и обновляется он вместе с браузером.
Это удобно представить как **лестницу аутентичности почерка** (от худшего к лучшему):
| Подход | Почерк | Свежесть | Мультиплексирование |
| --- | --- | --- | --- |
| **uTLS-пресет** (`chrome`/`firefox`) | копия, перечислимая | протухает (нужно ждать новый пресет) | нет (нужен отдельный mux) |
| **NaiveProxy** (Chromium `//net`/cronet) | подлинный стек Chromium | **отстаёт**: автор вручную линкует свежий хромиум; на момент обсуждения был Chrome 149, а Naive — на сборке ~148.x | да, естественный HTTP/2 |
| **XHTTP + Browser Dialer** (Xray) | подлинный — TLS делает **реально установленный в системе браузер** | **моментальная**: берётся любой обновлённый браузер из системы | да, в паре с **XMUX** (`maxConnections`) |
> [!tip] Закрывает сразу две оси — но **двумя рычагами**, не «одной галочкой»
> Подлинный стек браузера даёт **массовый настоящий фингерпринт** — это **Сигнал 2** (дорого банить, не «протухает», как пресет). А вот поведенческую ось (**Сигнал 3**) закрывает **не сам почерк, а транспорт**: HTTP/2 + `XMUX`. У **NaiveProxy** мультиплексирование нативное (HTTP/2 в cronet); у **Browser Dialer** его нужно **включить отдельно** — `XMUX`/`maxConnections` в XHTTP, само по себе оно не появляется. То есть это **два рычага в связке** (подлинный почерк + mux), а не один инструмент «из коробки» — зато оба живут в одном клиенте, тогда как «uTLS + отдельный mux» собираются из более хрупких частей. Про поведенческую ось — см. раздел про **mux** в этой заметке; `XMUX` в xhttp придумали ещё **до** «сибирской» схемы — изначально ради пулинга соединений под CDN, но как **побочный эффект** это и сглаживает лавину (Сигнал 3).
Нюансы (по сообщениям сообщества, не как гарантия):
- **NaiveProxy** всё ещё **не свободен от устаревания**: cronet-стек влинкован под конкретную сборку Chromium, и пока автор не пересоберёт под новый — поведение свежего Chrome может отличаться в деталях. То есть Naive **уменьшает** разрыв с реальным браузером, но не обнуляет его.
- **Browser Dialer** использует **уже установленный** браузер, поэтому переход на новую версию мгновенный и попугайства нет вообще — но цена в том, что нужен живой браузер/вкладка-«диалер» рядом с клиентом (UX-издержка); по сообщениям, на Android рабочий вариант.
- Это **клиентский** путь: почерк генерится **на устройстве пользователя**, до цензора — ровно то, о чём [[mtproxy/ja4-sni-client-side|«JA4 и SNI меняет только клиент»]]. Серверная сторона тут по-прежнему ничего не решает.
> [!warning] Не «серебряная пуля»
> Подлинный почерк снимает только **Сигнал 2** (фингерпринт) и, через XMUX/HTTP-2, **Сигнал 3** (частоту). **Сигнал 1 (подсеть VPS)** остаётся — его убирает только CDN-фронтинг (см. ниже «Что реально помогает против сигнала подсети»). И сам по себе подлинный стек не прячет **TLS-в-TLS** — это отдельная ось (Vision/padding).
### Имеет ли смысл держать на VPS свою страничку и использовать её как SNI?
**Для REALITY — нет, это ломает саму идею.** REALITY не использует ваш домен — он **заимствует TLS-личность чужого популярного сайта**: вы указываете `target`/`dest` = реальный внешний сайт, REALITY ретранслирует к нему рукопожатие, и наблюдатель видит **настоящий сертификат этого сайта**. Своя страничка как SNI:
- **теряет заёмную репутацию** (а это весь смысл REALITY) — неизвестный `myhomepage.tld` репутации не имеет;
- **не входит в SNI-whitelist** — при белых списках неизвестное имя *подозрительнее* знаменитого;
- **концентрирует частоту** — весь трафик на один свой SNI = ровно та аномалия «много к одному редкому имени», которую ловит Сигнал 3.
Decoy-сайт (своя страница + nginx-fallback) — это про **классическую** маскировку (Trojan / VLESS + реальный сертификат) и помогает он против **активного зондирования**, а не против этой пассивной схемы. Если уж REALITY напрямую на VPS — берите чужой *знаменитый* SNI, не свой.
### Не устарел ли сам REALITY? (сверка пары SNI↔IP)
Отдельный довод, который звучит у практиков: REALITY становится уязвим к **сверке пары SNI↔IP**. Вся идея REALITY — *заимствовать* чужой знаменитый SNI (например `www.microsoft.com`), но соединение при этом идёт на **ваш VPS-IP**, а не на реальные адреса Microsoft. Пассивный цензор, ведущий карту «какой SNI обычно ходит на какие IP/ASN», может ловить **рассогласование**: в `ClientHello` заявлен `www.microsoft.com`, а пакет летит в случайную подсеть хостинга. Активное зондирование тут ни при чём — это **пассивная** проверка, и фирменная защита REALITY «отдать настоящий серт на пробу» от неё **не спасает** (это другая ось).
> [!warning] «REALITY бесполезен» — это гипербола
> Сверка SNI↔IP **дорога цензору**: легитимных рассогласований масса (CDN, ECH, сплит-DNS, корпоративные прокси), поэтому массовая проверка даёт ложные срабатывания на обычном трафике — тот же «сопутствующий ущерб», что и с подсетями. Корректнее формулировать как «вектор реален и REALITY **слабеет**», а не «мёртв». И главное: это **мнение/прогноз практиков**, а **не** подтверждённая часть «сибирской» схемы — в первоисточнике три сигнала (подсеть, фингерпринт, частота), **сверки SNI↔IP там нет**.
Это **родственная** логика той, что осторожно отмечена для MTProto в [[mtproxy/ja4-sni-client-side|проверке SNI на резолвимость]]: в обоих случаях цензор сверяет заявленное имя с реальностью соединения. Но **сами проверки разные**: для MTProto — *резолвится ли SNI вообще* (есть ли A-запись); для REALITY — *совпадает ли SNI с IP назначения*. И там, и там это пока **гипотеза о развитии DPI**, а не зафиксированное правило.
И ещё довод против «фирменности» REALITY: его защита от активного зондирования — это **fallback** (редирект неаутентифицированных проб на `dest`-бэкенд, «spider mode»), и поведенчески она воспроизводится **десятком строк** в caddy/nginx (обычный TLS + fallback на реальный сайт). То есть по-настоящему уникальна у REALITY именно **заёмная личность** чужого *удалённого* сайта — а её как раз и подтачивает сверка SNI↔IP. (Для ясности: **self-steal** — это не защита, а *топология* REALITY, где `dest`/`target` смотрит на **свой локальный** decoy, т.е. ровно тот самый «своя страница + nginx-fallback», только средствами REALITY — противоположность заимствованию чужого сайта.) При этом против самого опасного, **Сигнала 1 (подсеть)**, REALITY не помогал никогда — поэтому общий вывод не меняется: структурный рычаг — **CDN-фронтинг** (см. ниже), а не выбор «магического» транспорта.
### Что реально помогает против сигнала «подозрительная подсеть»?
Все локальные меры (свежий пресет, mux, разные SNI, выбор провайдера) **не убирают Сигнал 1** — подсеть VPS остаётся подозрительной. Единственный рычаг, который **структурно** его убирает, — спрятать назначение за **большим CDN**:
- **VLESS over XHTTP / WebSocket за Cloudflare.** Цензор видит соединение к **IP Cloudflare** (огромный, де-факто whitelisted), а не к вашему VPS — сигнал подсети исчезает, потому что меняется *сам адрес, который видит цензор*.
- **Цена честно:** CDN терминирует ваш TLS и **видит трафик** в открытом виде; **медленнее** (крюк через edge); **ToS-серая зона** для тяжёлого/видео-трафика.
- Важно: сам REALITY за CDN так не ставится — ради CDN меняют транспорт (XHTTP/WS).
#### Что от чего помогает: active probing vs пассивная схема
| Мера | Против active probing | Против пассивной схемы (подсеть + фингерпринт + частота) |
| --- | --- | --- |
| REALITY со **знаменитым чужим** SNI | ✅ | ⚠️ частично — знаменитый SNI размывает частоту, но **подсеть не меняется** |
| REALITY со **своим decoy-SNI** | ✅ | ❌ хуже — редкий SNI концентрирует трафик; подсеть та же; не в whitelist |
| Классика VLESS/Trojan + свой серт + nginx-fallback | ⚠️ частично | ❌ — свой домен + та же подсеть |
| **CDN-фронтинг** (VLESS+XHTTP/WS за Cloudflare) | ✅ | ✅ **единственный рычаг, убирающий сигнал подсети** (цена: CDN видит трафик, медленнее, ToS) |
### Прямое подключение vs каскад — спасает ли это от Сигнала 1?
Короткий ответ: **нет — решает не топология, а флагнутость подсети первого хопа.**
Сигнал 1 смотрит **не на вашу домашнюю подсеть** (residential-IP в РФ), а на **подсеть назначения того соединения, которое видит DPI** — то есть на **первый хоп**, сервер, к которому вы открываете TLS.
- **Прямое `юзер → eu-нода`.** DPI видит соединение к зарубежному серверу. И зарубежные хостинги **тоже** в списке подозрительных — более того, они там были **изначально**: старые методы (`tcp 16-20` / `l4-25`) били **только** по зарубежным провайдерам (Hetzner, DigitalOcean, OVH). Новизна «сибирской» схемы — что к ним **добавили** российские ДЦ, а не заменили. Так что прямое подключение к VPS на Hetzner/DO **спокойно попадает** под Сигнал 1.
- **Каскад `юзер → ru-нода → eu-нода`.** DPI видит вход — **ru-ноду**. Если она на Selectel/Яндекс.Облаке, это **теперь тоже** подозрительная подсеть, то есть каскад через российский ДЦ стало только **хуже**. (Хоп ru→eu — исходящий трафик сервера, ваш DPI его как клиентское рукопожатие не оценивает.)
Сигнал 1 **не срабатывает** не «при прямом» и не «при каскаде», а когда подсеть первого хопа **вообще не в списке**: residential/мобильные IP, большой CDN (поэтому CDN-фронтинг и есть структурный рычаг), редкий «чистый» провайдер. Hetzner напрямую и Selectel через каскад «горят» одинаково; residential или CDN — нет, в любой топологии.
> [!quote] Оговорка
> Точный состав списка подозрительных подсетей публично неизвестен (реверс-инжиниринг одного автора). Вывод «зарубежные тоже в списке» следует из формулировки первоисточника («затронуты подсети/AS, **в т.ч.** российских ДЦ, в отличие от методов, бивших **только** по зарубежным»), а не из опубликованной спецификации.
### Разве XTLS Vision не маскирует большое количество TLS-соединений?
Частая путаница. **Нет — Vision маскирует не *количество* соединений, а *форму* TLS-в-TLS внутри одного соединения.**
- Vision (`xtls-rprx-vision`) решает проблему **«TLS-in-TLS detection»**: когда прокси несёт внутренние TLS-записи внутри внешнего TLS, возникает узнаваемый вложенный паттерн (характерные размеры записей). Vision добавляет padding в раннюю фазу рукопожатия и затем переключается на прямое `splice`-копирование в ядре — внешне трафик перестаёт выглядеть как «TLS в TLS».
- Но Vision работает **по-соединению** и **ничего не объединяет**. Каждое проксируемое соединение — это всё равно свой отдельный внешний TLS+TCP-коннект к серверу. Браузер открыл 10 вкладок → 10 внешних TLS-соединений на один SNI. Это ровно территория **Сигнала 3**.
- Объединяет много логических потоков в одно физическое соединение — это **`mux`**, а не Vision. И именно поэтому они конфликтуют (см. раздел про mux выше): Vision требует «сырого» TCP под splice, а mux оборачивает поток.
Вывод: Vision прячет *вложенность* TLS, но **не уменьшает число соединений**. Против поведенческого Сигнала 3 он не помогает — это задача mux (несовместимого с Vision) либо разнесения по разным SNI и сдержанного паттерна.
Именно из этой несовместимости вырос популярный слух «в России без flow работает лучше»: у части домашних провайдеров с ноября 2025 года помогала связка «пустой flow + mux», где отказ от Vision был техническим условием для mux, а не самостоятельным обходом. Разбор случая с первоисточниками — в [[xray/vless-stack-map|карте слоёв VLESS-стека]], раздел про пустой flow.
### Vision, mux и «TLS-в-TLS» — три вещи, которые путают
Самый запутанный узел. Тут сходятся **три независимых** понятия — разведём их:
| Ось | Что это | Чем управляется |
| --- | --- | --- |
| **Security** (`reality`/`tls`) | чьей TLS-личностью представляется внешний туннель | выбор `security` |
| **TLS-в-TLS** | вложенность: сайт-TLS *внутри* туннеля | возникает сам при HTTPS-сёрфинге → лечит **Vision** |
| **Число внешних соединений** | сколько отдельных TCP+TLS к серверу | `mux` (вкл/выкл) → считает **Сигнал 3** |
Главное: **`reality` vs `tls` НЕ решает «отдельные коннекты или один поток»** — это решает `mux`. И reality, и tls по умолчанию дают одно внешнее соединение на коннект и оба несут TLS-в-TLS.
К этим трём осям с конца августа 2025 добавилась четвёртая — `encryption`, то есть [[xray/vless-encryption|шифрование самого протокола VLESS]]. Маскировку она не заменяет: её собственный внешний вид спрятан внутри туннеля, а снаружи наблюдатель видит всё тот же внешний слой. Зато она снимает старое ограничение «Vision только на прямом TCP» и даёт настраиваемую набивку рукопожатия — RPRX в ноябре 2025 предлагал вложить её внутрь REALITY именно как способ поменять признаки трафика без правки кода. Полная матрица сочетаний — в [[xray/vless-stack-map|карте слоёв VLESS-стека]].
**Что такое TLS-в-TLS** (с этим борется Vision). Открываете `https://google.com` через туннель — получаются два вложенных слоя TLS:
![[wiki-anim-tls-in-tls.svg|Схема: TLS в TLS — два вложенных соединения]]
Даже ОДНО соединение уже имеет эту вложенность: размеры записей внутреннего рукопожатия «просвечивают» сквозь внешний слой. Vision добавляет padding и переключается на splice, чтобы внутренний почерк не просвечивал. Это есть и при `reality`, и при `tls`.
**А «один большой поток с кучей рукопожатий» — это `mux`** (а не `security: tls`!):
![[wiki-anim-mux.svg|Схема: одно внешнее TLS-соединение несёт несколько подпотоков]]
Много потоков в одном коннекте → меньше внешних соединений → бьёт по Сигналу 3. Но Vision на mux-поток **не накладывается** — ему нужен «сырой» отдельный TCP под splice, поэтому Vision и mux **взаимоисключающие**.
> [!summary] Развязка
> - **Vision** лечит **TLS-в-TLS** (форму *внутри* одного соединения) — это отдельный детект, **не** из «сибирской» тройки.
> - **mux** лечит **число соединений** (Сигнал 3).
> - Они чинят разные болезни и **взаимоисключающи** — выбираете что-то одно.
> - `security` (reality/tls) — только про то, *чьим* сертификатом представляется туннель; к «коннекты vs поток» отношения не имеет.
### Можно ли вылечить обе болезни сразу?
Раз Vision и mux взаимоисключающие — обречены ли мы выбирать? **Нет.** И тут важное переосмысление: сам конфликт — **не «защита против защиты»**.
Vision склеивает две разные вещи:
- **padding** — добивает короткие пакеты ранней фазы рукопожатия → это и есть **анти-детект** TLS-в-TLS;
- **splice** — после рукопожатия копирует поток прямо в ядре Linux → это **оптимизация производительности**, и только.
С mux несовместим именно **`splice`** (ему нужен «сырой» 1:1 поток), а **не `padding`**. То есть настоящий трейд-офф — **«padding + splice-скорость» против «мультиплексирования»**, а не «один детект против другого». Splice — это то, чем жертвуют, а не защита. **Значит, обе болезни лечатся одновременно — ценой отказа от splice-ускорения.**
**Практическое воплощение — транспорт XHTTP + XMUX** ([«XHTTP: Beyond REALITY», #4113](https://github.com/XTLS/Xray-core/discussions/4113)) — VLESS поверх HTTP/2 или H3:
- **число соединений** лечит **XMUX** (объединяет логические запросы в одно физическое соединение) — ✅;
- **форму TLS-в-TLS** размывает (header-padding `xPaddingBytes` + разнесение upload/download + перемешивание потоков);
- **совместим с REALITY** и **работает за CDN** — а это убирает заодно и Сигнал 1 (подсеть становится CDN'овской).
| | Vision + REALITY (raw TCP) | XHTTP + XMUX (+ REALITY/CDN) |
| --- | --- | --- |
| TLS-в-TLS | ✅ padding + splice (сильнее по форме) | ⚠️ padding + split + mux (статистически, слабее) |
| Число соединений (Сигнал 3) | ❌ (mux нельзя) | ✅ XMUX |
| Подсеть (Сигнал 1) | ❌ | ✅ если за CDN |
| Скорость | ✅ splice | ❌ всё через userspace (медленнее) |
> [!warning] Честная оговорка
> XHTTP прячет TLS-в-TLS **слабее**, чем кажется. По [USENIX Security 2024](https://www.usenix.org/conference/usenixsecurity24/presentation/xue-fingerprinting) («Fingerprinting Obfuscated Proxy Traffic with Encapsulated TLS Handshakes») padding + мультиплексирование «многообещающи, но **принципиально ограниченны**»: они не уменьшают размер всплесков и число round-trip'ов, по которым вложенное рукопожатие и палится. XHTTP делает детект **статистически дороже**, а не невозможным. *Почему* именно — разобрано ниже, в пункте про round-trip'ы.
**Итог:** вылечить обе можно (XHTTP+XMUX), цена — потеря splice-скорости (а не принципиальный запрет) плюс «статистический», а не идеальный анти-TLS-в-TLS. Поэтому XTLS рекомендует держать **оба профиля** на сервере: `Vision+REALITY+TCP` для скорости/прямого подключения и `XHTTP+XMUX` для стелса/CDN (популярная «5-в-1» конфигурация).
### А kTLS — вернёт ли он потерянную скорость?
**kTLS** (Kernel TLS) — функция ядра Linux, переносящая шифрование/расшифровку TLS-записей **в ядро**. За счёт этого forwarding может работать с zero-copy (`sendfile`/`splice`) даже когда прокси сам терминирует TLS. В xray это обсуждается ([discussion #4270](https://github.com/XTLS/Xray-core/discussions/4270), [issue #2565](https://github.com/XTLS/Xray-core/issues/2565)) как способ получить splice-уровень производительности **без** XTLS Vision — в обычном TLS-проксировании.
Но важно, чем kTLS **не** является:
- Это **только производительность**, не анти-детект. Он ничего не прячет — ни форму TLS-в-TLS, ни число соединений.
- Он **не отменяет** дилемму mux↔splice: ядерное копирование всё равно несовместимо с мультиплексором, который оборачивает поток в свои фреймы.
- В xray это пока **экспериментально / на стадии обсуждения**, а не готовая кнопка.
Грубо: kTLS — рычаг «вернуть часть CPU и скорости», **ортогональный** детекту. На вопрос «как спрятаться» он не отвечает; он про «как сделать это дешевле по ресурсам».
### Почему padding и mux в принципе не прячут TLS-в-TLS (детект по round-trip'ам)
Самый глубокий уровень — *почему* padding и мультиплексирование лишь полумеры **против детекта TLS-в-TLS**. (Важно: это отдельный вектор, **не** «сибирский» Сигнал 3 — число параллельных соединений mux по-прежнему уменьшает; речь о том, что *форму* вложенного рукопожатия полностью спрятать не удаётся.) Объясняет это [USENIX Security 2024](https://www.usenix.org/conference/usenixsecurity24/presentation/xue-fingerprinting).
TLS-рукопожатие — это характерная **хореография**: всплеск пакетов от клиента → пауза в один **RTT** (round-trip) → ответный всплеск от сервера → снова пауза → и т.д. Когда такое рукопожатие идёт **внутри** туннеля, эта последовательность «всплеск — пауза RTT — всплеск» **просвечивает наружу** узнаваемым ритмом в начале соединения.
И вот суть, почему обфускация не спасает:
- **padding** меняет *размеры* пакетов — но **не меняет число round-trip'ов** и не убирает структуру всплесков. Ритм остаётся.
- **mux** перемешивает потоки — но при малой нагрузке (один-два активных потока) перемешивать нечего, и начальное рукопожатие сохраняет свой round-trip-узор.
Поэтому детектор смотрит не на байты, а на **последовательность всплесков, их направления и паузы между ними** — и опознаёт «внутри идёт TLS-рукопожатие». Это устойчиво к padding'у и частично к mux'у.
Цифры из той работы стоит приводить аккуратно, потому что их постоянно сравнивают между собой некорректно — они относятся к разным конфигурациям и разным моделям. Набивка у vmess поверх WebSocket и TLS снижает TPR (долю верно распознанных прокси-потоков) с **0,859 до 0,687**, причём авторы отдельно оговаривают, что схема набивки у vmess узкая — 0–63 байта. Для XTLS-Vision модель переучили так, чтобы она опиралась на направления и порядок пакетов, а не на их индивидуальные размеры; у неё TPR **0,513**, но при вчетверо большем допуске ложных срабатываний (0,199 % против 0,054 %). То есть «51 %» — это не «Vision сбил детект с 70 % до 51 %», а результат другой модели на другом пороге. Мультиплексирование в тех же измерениях эффективнее: у голого vmess объединение двух потоков роняет TPR с 0,771 до 0,225 — более чем на 70 %, — а vmess поверх WebSocket и TLS при восьми параллельных потоках опускается до **0,125**. Ключевая оговорка: при одном активном прикладном потоке перемешивать нечего, и mux деградирует до уровня обычного соединения.
> [!summary] Что нужно для настоящей защиты
> По выводам статьи — не *дополнять* трафик, а **переформировывать** его: уменьшать размер всплесков и число round-trip'ов внутри соединения. Готового решения, полностью закрывающего это, в современных клиентах пока нет. Отсюда и фундаментальность гонки: обфускация поднимает *стоимость* детекта, но не делает его невозможным.
### Можно ли mux без head-of-line blocking?
Раз у mux есть болячка HoL (потеря одного пакета тормозит все потоки) — можно ли мультиплексировать без неё? **Можно, и это уже сделано** — но сначала о корне.
**Откуда берётся HoL.** TCP — это **один упорядоченный надёжный байтовый поток**. Mux поверх него гонит все логические потоки через этот единый поток. Потерялся пакет → TCP держит всё, что пришло **после** него, пока не дождётся повтора — даже данные других потоков, которые уже дошли целыми. Это **неизбежно** для любого mux поверх одного TCP: ни Mux.Cool, ни HTTP/2 не уйдут — они все сидят на одном TCP-потоке (HTTP/2 убрал HoL на уровне приложения, но не транспорта).
**Выход — не использовать единый TCP-поток.** Надо дать каждому логическому потоку **свою независимую упорядоченность**. Это умеет **QUIC (= HTTP/3)**: работает поверх UDP и реализует надёжность/порядок **на каждый поток отдельно**. Потерянный пакет блокирует только свой поток — остальные едут дальше. Ради этого QUIC и придумали.
**В xray это уже есть:** XHTTP поддерживает **H3-режим** (QUIC) → XMUX поверх QUIC = мультиплексирование **без TCP-HoL**.
> [!warning] Подвохи — почему это не дефолт
> - **QUIC = UDP, а UDP легко душат.** Цензор может троттлить/резать UDP или QUIC целиком (в РФ бывает) → откат на TCP, и HoL возвращается. Отсюда же `xudpProxyUDP443: reject` (форсить откат QUIC на TCP).
> - **QUIC не прячет детект.** Round-trip'ы вложенного рукопожатия (см. пункт выше) просвечивают и через него — QUIC лечит *производительность/HoL*, а не *обнаружимость формы*.
> - **Цена и совместимость.** QUIC — userspace, дороже по CPU; поддержка H3 у CDN/промежуточных узлов неровная.
**Итог:** HoL **неустраним** поверх одного TCP — это закон. Обойти = перейти на per-stream-транспорт (**QUIC/H3**, XHTTP умеет), но вы меняете «HoL + надёжный TCP» на «без HoL, но по UDP, который цензор может прибить» — и форму трафика это всё равно не лечит. Бесплатного обеда нет.
---
## 🎯 Главный вывод
Эпоха «поставил REALITY и забыл» закончилась. DPI перешёл от анализа **содержимого** пакета к анализу **поведения** соединения. Отсюда три следствия:
1. Идеальная криптография **больше не гарантирует** невидимость — она необходима, но недостаточна.
2. Решает не один параметр, а **совокупность косвенных признаков** (подсеть + фингерпринт + поведение).
3. Устойчивость даёт не «волшебная галочка», а **грамотный профиль целиком**: правильная подсеть, лояльный фингерпринт (uTLS), сдержанный паттерн соединений (mux + разные SNI).
Гонка щита и меча перешла на уровень статистики и поведения. Выигрывает тот, чей трафик **скучный** — максимально похожий на обычного пользователя и снаружи, и внутри.
---
## 📚 См. также
- 🔗 **Первоисточник:** [habr.com/ru/articles/1044396](https://habr.com/ru/articles/1044396/) — Пётр Осетров (@hyperion_cs)
- 🔗 [uTLS — refraction-networking/utls](https://github.com/refraction-networking/utls)
- 🔗 [dpi-checkers — hyperion-cs/dpi-checkers](https://github.com/hyperion-cs/dpi-checkers)
- 🔎 **Как это измерить:** [[DPI/tspu-inspectors-checkers-2026|Инспекторы ТСПУ: шесть чекеров блокировок]] — в том числе проверка «сибирского» ограничения по числу одновременных рукопожатий в `dpi-ch`
- 🔗 [xray-core — XTLS/Xray-core](https://github.com/XTLS/Xray-core)
- 🔍 **Парная заметка:** [[dpi-analysis-pipeline|Как DPI анализирует соединение: воронка проверок (от SYN до ML)]] — общий конвейер, в который вписана эта схема
- 🦎 **Парная заметка:** [[statistical-morphing-concept|Адаптивная мимикрия: статистический морфинг трафика]] — концепт, как *можно было бы* обойти поведенческий сигнал
- 🕵️ **Полевой кейс:** [[DPI/browser-ja4-fingerprint-block|Блокировка сайта по JA4-отпечатку браузера]] — «Сигнал 2» в дикой природе: сайт не открывается только в Chrome/Edge
- 💥 **Побочный ущерб:** [[DPI/tspu-false-blocks-june-2026|Как ТСПУ ломает легитимные сайты (июнь 2026)]] — те же три сигнала, но бьющие по обычным сайтам на хостингах, а не по обходным средствам
- 📈 **Прогноз:** [[DPI/vpn-blocking-wave-forecast-summer-2026|Новая волна блокировок VPN (лето–осень 2026)]] — эта июньская схема в контексте ряда волн 2026 года; что в прогнозе подтверждено, а что остаётся экспертной гипотезой без даты
- [[Zapret/about|Что такое обход DPI: VPN, Tor, DPI]]
- [[Zapret/premium|premium]] — рабочие конфиги
- [[Zapret/vless-sni|Список SNI для VLESS]]
- [[VLESS-localhost-protection-guide|Защита VLESS на стороне localhost]]
- [[VLESS-SOCKS5-vulnerability|Уязвимость VLESS + SOCKS5]]