О чем материал
Разбираемся, как устроены современные VPN-протоколы и за счет чего можно обнаружить даже самые сложные механизмы маскировки
Анализ сетевого трафика принято считать непопулярной, узкой темой «для своих». Услышав эти слова, вы наверняка представляете себе бородатых администраторов, которые протягивают сеть и настраивают Cisco (что, разумеется, правда). Или наоборот: вы знаете, что ловить хакеров по сетевым следам гораздо легче, чем на хосте.
Так или иначе, у большинства из нас слова «анализ сетевого трафика» раньше не вызывали в голове знакомые образы и оставались где-то вдалеке. Все изменилось в 2020-х с началом активной фильтрации трафика магистральными операторами в России. Именно в тот момент многие впервые услышали слова «пэддинг» (padding), «дипиай» (DPI) и «Zapret».
Теперь VPN-протоколы и окутанные тайной магистральные DPI-системы играют в кошки-мышки, нанося друг другу блокировки и маскировки. В разные углы ринга разошлись два больших зверя:
- В левом углу: DPI (Deep Package Inspection) в составе магистральных систем по анализу трафика. Это технология глубокого анализа сетевых пакетов и поиска в них чего угодно.
- В правом: современные VPN-протоколы из Xray-Core. Например, Vless — протокол обхода систем анализа, который эффективно мимикрирует под жизненно важные интернет-сервисы.
Мы уже больше 10 лет занимается анализом сетевого трафика и разработкой алгоритмов обнаружения хакеров вместе со специалистами по ML. За это время мы убедились, что лишь немногие знают, как эффективно прятать сетевые следы от стороннего наблюдателя и как их находить. Авторы так называемых Anti-DPI-протоколов то и дело допускают нелепые ошибки и оставляют красные флаги прямо в интерфейсе WireShark.
WireGuard и Amnezia
Протокол WireGuard обеспечивал непревзойденную скорость за счет того, что клиентская и серверная части были написаны в виде драйверов, а сетевые пакеты передавались по UDP-транспорту и подвергались быстрому шифрованию. Однако у него был серьезный недостаток: обнаружить WireGuard в сети было проще простого. Ровно это в итоге и произошло: 30 апреля 2025 г. все интернет-провайдеры перестали пропускать протокол за рубеж. Ранее аналогичные ограничения уже вводились в отношении OpenVPN и L2TP.

В начале соединения клиент и сервер WireGuard производят так называемый HandShake, то есть обмениваются параметрами подключения и ключами шифрования, после чего происходит обмен данными. Тип сообщения, который соответствовал каждому из этапов, указывался в первых четырех байтах: 0x01000000, 0x02000000 либо 0x04000000. Вкупе с фиксированными размерами пакетов и нулевыми полями mac и counter внутри них это помогало однозначно идентифицировать протокол среди сетевого трафика.
Ответку придумали авторы Amnezia (причем чуть раньше начала блокировок WireGuard). По их словам, они создали усовершенствованную версию протокола: «WireGuard известен своей эффективностью, но у него есть проблемы с обнаружением из-за характерных сигнатур пакетов. AmneziaWG решает эту проблему за счет использования более эффективных методов обфускации — VPN-трафик сливается с обычным. Протокол не распознается системами DPI-анализа и устойчив к блокировке». Но так ли это?

На первый взгляд, многое поменялось. Уже нет тех нулей в начале и в конце пакета, за которые легко цеплялся взгляд. Получается, создателям Amnezia удалось избавиться от статичной сигнатуры и обойти DPI? Как бы не так! Да, разработчики ввели девять дополнительных параметров соединения (S1-S2 H1-H4 Jc Jmax Jmin), которые меняют статические байты с номерами команд и рандомизируют длину сообщений. Но на рис. 2 можно заметить длинное поле с нулями по адресу 0x0032. Это 8-байтовое поле counter, которое увеличивается на единицу с каждым новым сообщением от клиента или сервера. А вторым важным признаком остается размер сообщений.

Итак, в сообщениях Amnezia все еще присутствуют последовательности пакетов с длинами 32 и 96 байт, как и в оригинальном WireGuard (см. рис. 3). Несмотря на то, что содержимое сетевых пакетов полностью зашифровано, размеры и временные промежутки между ними могут поведать о многом. Последовательность длин и время между отправкой пакетов называется «побочным каналом», который есть у любого зашифрованного соединения.
Спустя время разработчики Amnezia выпустили обновленную версию протокола Amnezia 2.0, которая способна искусно маскироваться под другие UDP-протоколы. Однако ее можно обнаружить по тем же признакам.
ShadowSocks
Протокол ShadowsSocks (SS) по нынешним меркам был придуман давным-давно — в 2012 г. — разработчиком из Китая в ответ на интернет-цензуру. SS — это усовершенствованная версия Socks5 с AEAD-шифрованием, замаскированная под TLS. Протокол полностью шифрует содержимое сообщений и не имеет «нулей», поэтому обнаружить его в сети сложнее, чем Amnezia. Однако взгляните на две сессии (см. рис. 4).

ShadowSocks может использовать протокол UDP для ускорения передачи. Изумительная последовательность UDP-пакетов длиной 76, 149, 94, 132 и 123 байт прямо прыгает с экрана на эксперта, чтобы превратиться в сигнатуру для обнаружения подключений :) К слову, такие очевидные длины пакетов мы называем «магическими».
Vless и семейство Xray
На сегодняшний день абсолютный лидер технологий борьбы с интернет-цензурой — протокол Vless (VMess Less). Он был разработан в 2020 г. в качестве замены устаревшему VMess (поскольку Великий Китайский файрвол (GFW) полностью блокировал VMess и ShadowSocks). VMess имел ряд архитектурных ограничений, которые были связаны с производительностью, сложностью реализации и избыточным шифрованием (например, привязку ко времени клиента и сервера), что не позволяло ему легко масштабироваться на тысячи подключений.
В конце 2020 г. сообщество разработчиков разделилось: создатель Vless ушел из Project V (VMess) и присоединился к Project X, чтобы сосредоточиться на развитии нового ядра Xray. Оно стало форком ядра V2Ray, но с существенно переработанной архитектурой. Помимо самого протокола Vless, Xray включает ряд дополнительных технологий, направленных на повышение производительности и устойчивости к обнаружению. Среди них особое место занимают:
- Reality — разработанная в 2023 г. технология, реализующая маскировку соединения под легитимный TLS-трафик;
- xtls-rprx-vision — механизм, созданный для усложнения анализа трафика DPI-системами.
Термины Vless и Xray практически стали синонимами, однако Vless представляет собой простой VPN-протокол с поддержкой аутентификации по строке UUID и минимальными накладными расходами. Vless практически не имеет встроенных механизмов шифрования: они сознательно отданы на откуп транспортному уровню его отдельных реализаций. А выбрать есть из чего: на данный момент популярная реализация Xray поддерживает транспорты TLS, Reality (Anti-DPI копия TLS), xHTTP, WebSocket и др. Зачем так много? Все они позволяют сильно менять внешний вид сетевых соединений Vless, чтобы запутать DPI-системы. Причем меняется не только содержимое пакетов, но и сам характер взаимодействия: вместо множества коротких TCP-сессий может использоваться одна длинная. Кроме того, некоторые транспорты (gRPC, xHTTP) позволяют интегрировать Vless в популярные CDN-системы, что кратно увеличивает ущерб при их блокировке.
При всем этом конфигурация Vless может использовать собственный слой криптографии, основанный на гибридном постквантовом обмене ключами и разных режимах шифрования пакетов, например:
- native — пакеты шифруются без обфускации;
- xorpub — публичный ключ обфусцируется с помощью XOR;
- random — трафик превращается в полностью рандомные данные.
На данный момент самые распространенные транспортные связки — это «TCP + Reality», «xHTTP + Reality» и «WebSocket + TLS». Причем конфигурация с xHTTP (или ее предшественником gRPC) стала пользоваться популярностью осенью 2025 г., когда многие интернет-провайдеры тестировали методы обнаружения и блокировки схемы «Vless + TCP + Reality».

Фактически, если клиент подключается к VPN с популярной конфигурацией «Vless + TCP + Reality», он сначала устанавливает TLS-соединение с VPN-сервером (Reality выглядит как TLS), а уже внутри него передает свой трафик. И, учитывая то, что сейчас веб-трафик составляет около 85–90% мирового трафика (подсмотрели в Гугле), несложно догадаться: целиком это соединение будет напоминать матрешку «outer TLS -> inner TLS -> HTTP» со всего лишь небольшим вкраплением заголовков Vless перед началом inner TLS.

На самом деле Xray поддерживает даже самую базовую конфигурацию Vless — raw tcp. В ней нет шифрования, поэтому в таком соединении можно увидеть, что именно представляет собой Vless. Оказывается, то самое вкрапление в виде заголовка имеет следующую структуру (см. рис. 7):

Как Xray борется с DPI-системами
Кроме разнообразия транспортов для противодействия системам анализа сетевого трафика, авторы Xray придумали механизмы Reality и xtls-rprx-vision (или просто Vision). Они помогают еще сильнее снизить количество наблюдаемых признаков, которые позволяют отличить трафик VPN от обычного HTTPS.
Главный борец с обнаружением — транспорт Reality (модификация TLS 1.3). Он не использует собственные TLS-сертификаты, а напротив, мимикрирует под указанный существующий ресурс. Чтобы сервер мог отличить своего клиента от цензора, в ClientHello применяется специально сформированное поле SessionId. Его первые 16 байт содержат зашифрованные данные: версию клиента, время отправки пакета и идентификатор сервера. Запрос случайного клиента (без специального SessionId) прозрачно проксируется на указанный камуфляжный сайт-заглушку (например yahoo.com). Это делает активное сканирование бесполезным.
При инициализации сервера Xray с конфигурацией Reality он устанавливает соединение с камуфляжным сервером и копирует TLS-параметры Server Hello, включая сертификат, длину сообщений и структуру рукопожатия. В результате TLS-handshake с VPN-сервером выглядит так же, как с настоящим сайтом. Однако есть важный нюанс. Если Reality копирует TLS-сертификат (например, Google или Yahoo), то при активном сканировании сервера цензор заметит несоответствие в адресе сервера и доменных именах внутри сертификата. Поэтому более надежной считается схема Self-Steal, когда на том же VPN-сервере развернут собственный сайт-заглушка, откуда reality «ворует» сертификат.
Дополнительный уровень маскировки обеспечивает паддинг-механизм xtls-rprx-vision. В этом режиме к передаваемым данным внутри транспортного соединения (TLS, Reality) добавляются нулевые байты. При этом паддинг не меняет сами данные — только размеры TLS-записей, что позволяет бороться с обнаружением TLS-in-TLS.
Одна ошибка, которая разрушила все
Если верить разработчикам ядра Xray, сочетание xtls-rprx-vision и Reality делает сигнатурный детект практически невозможным. Случайный паддинг и маскировка под легитимные сайты сделали трафик Vless неотличимым от обычного веб-трафика. Однако у нас теплилась надежда на то, что даже при наличии случайного паддинга в передаваемых по тоннелю данных все равно можно увидеть того самого слона в удаве (TLS-in-TLS).
Мы решили собрать как можно больше сетевых VPN-сессий и применить машинное обучение. Развернули отдельную бот-ферму, которая круглосуточно генерировала трафик различных конфигураций Xray (vless, vmess, trojan + tls, reality) и имитировала браузерную активность обычного человека.
После сбора и обработки более 140 млрд сетевых сессий мы обучили ML-модель на основе алгоритма решающих деревьев — бустинга. Среди извлекаемых признаков использовали последовательность длин TLS-пакетов от клиента и сервера, а также статистические агрегаты над ними (min, max, mean, percentile). Подготовка и разметка данных заняли много времени: результат напрямую зависел от их качества, даже одна ошибка могла испортить весь эксперимент. В итоге наши усилия были вознаграждены: ML-модель начала верно отличать VPN-соединения, в основном по первым TLS-пакетам. Фактически она нащупала момент передачи внутреннего TLS-рукопожатия клиента к целевому серверу.

При анализе интерпретации модели мы заметили устойчивую закономерность: почти во всех VPN-соединениях в начале встречались TLS-пакеты длиной 1203 байта. Причем такой пакет зачастую сначала отправлял клиент, а сразу за ним — сервер. В трафике встречались и более крупные пакеты, однако закономерность выглядела неслучайной. Почему оба сообщения так аккуратно «обрезаются» именно на длине 1203 байта, словно MTU? Чтобы разобраться в этом, нам пришлось изучить исходные коды ядра Xray и дойти до… GO-библиотеки crypto/tls.


На рис. 9 и 10 отчетливо видны длина оригинального пакета — 1203 байта, поля протокола Vless внутри и самый первый пакет Client Hello к серверу nvidia. Но что еще интереснее, нули и в первом, и во втором пакетах — это тот самый паддинг, который добавляет механизм xtls-rprx-vision. Этого паддинга было так много, что клиенту Xray пришлось подробить один Client Hello-запрос от клиента аж на два пакета. Но откуда все-таки взялось число 1203?
О том, как мы расшифровываем TLS-соединения разных клиентов, включая Xray, можно прочесть в канале ESCalator.
Как оказалось, ядро Xray здесь ни при чем: в Go реализован механизм оптимизации передачи данных по TLS — dynamic record sizing. Его задача заключается в снижении задержки на старте соединения. Вместо того, чтобы сразу формировать крупные TLS-записи (до 16 килобайт), библиотека сначала отправляет сравнительно небольшие записи, а затем постепенно увеличивает их размер по мере роста объема переданных данных. Ключевую роль играет константа tcpMSSEstimate, равная 1208 байтам. Это консервативная оценка TCP MSS, рассчитанная исходя из минимального MTU для IPv6 (1280 байт) за вычетом заголовков IPv6 и TCP. Библиотека старается подобрать такой размер полезной нагрузки, чтобы итоговая TLS-запись целиком помещалась примерно в один TCP-сегмент. С учетом 5 байтов заголовка TLS, получаем те самые 1203 байта полезной нагрузки. Именно поэтому первый TLS-пакет Application Data после завершения handshake с VPN-сервером часто имеет эту длину. Стоит отметить, что такое поведение характерно как для IPv4, так и для IPv6.
Этот механизм объясняет наблюдаемую картину. После завершения внешнего TLS-рукопожатия клиент отправляет внутренний Client Hello. Его размер часто превышает 1203 байта, поэтому он делится на два TLS-чанка: 1203 байта и остаток. Сервер, в свою очередь, отвечает внутренним Server Hello, который делится точно так же. Причем размер паддинга, который добавляет Xray, рассчитывается почти случайно в примерном диапазоне 900–1400 байт и зависит от исходной длины данных. Дальше в сессии мы не увидим длин 1203, поскольку значение этого «ограничителя» внутри библиотеки crypto/tls растет кратно с каждым пакетом.
Получается, что механизм Vision не только не помогает уйти от обнаружения системами DPI, но и создает самый красный из всех флагов. Хотя наблюдать такое поведение мы будем и без Vision: размеры TLS Client и Server Hello обычно и без паддинга достаточно большие.
Таким образом, мы получили воспроизводимый поведенческий признак: сразу после завершения TLS-handshake наблюдаются две последовательные TLS-записи длиной 1203 байта (сначала от клиента, затем от сервера). Отмечу, что это не артефакт Xray в чистом виде: формально детект фиксирует соединение между TLS-клиентом и TLS-сервером, написанными на Go с использованием той самой библиотеки. Однако на практике, в интернете, такое встречается крайне редко. Научив ML-модель в целом обнаруживать признаки TLS-in-TLS и добавив пороги срабатывания, мы получили ровно ноль ложноположительных срабатываний в нашей инфраструктуре.
Как обойти такой детект
Несмотря на название, тут не будет конкретных инструкций для обхода детекта.
Во-первых, противостояние современных VPN-протоколов и DPI-систем — это так называемая борьба брони и снаряда. Обе стороны постоянно придумывают что-то новое, поэтому наш материал быстро устареет. Например, последние версии Xray стали не только имитировать параметры TLS от сайта-клона (сертификат и шифры), но и пересылать от него первые пакеты с данными. Такое поведение похоже на обмен «мусором» в начале соединения по протоколу Amnezia, которое обходит некоторые DPI-системы.
Во-вторых, такой детект пока реализован только в нашем PT NAD.
В-третьих, разные клиенты Vless и их транспорты уже неплохо справляются с этой задачей. Найденное нами магическое число 1203 наблюдается только в ядре Xray и на определенных транспортах, где клиент или сервер передают в начале большие данные (так, в xHTTP длин 1203, скорее всего, не будет). К тому же, помимо Xray, есть и другие реализации Vless (например, sing-box, Clash и Clash.Meta), которые могут быть написаны с использованием других библиотек.





