Народный

Безопасность

Padding и junk-пакеты: как AmneziaWG обходит ТСПУ

Команда vpn-rating.xyz · · ⏱ 6 мин
§ в этой статье — 12 разделов

Стандартный WireGuard — это поток UDP-пакетов с почти арифметически предсказуемой структурой handshake’а. ТСПУ ловит его одним правилом за миллисекунды. AmneziaWG — форк, в который добавлены параметры обфускации, и именно эти параметры превращают «легко детектируемый WireGuard» в «случайный UDP-шум». Разбираем, что они делают.

Проблема стандартного WireGuard

WireGuard RFC-определяет первый пакет handshake’а (HandshakeInitiation) как структуру фиксированной длины 148 байт:

+----+----+----+----+
| type=1 | 0x00 0x00 0x00  (4 байта)
+----+----+----+----+
| sender index            (4 байта)
+----+----+----+----+
| ephemeral pubkey        (32 байта)
+----+----+----+----+
| encrypted static key    (48 байт)
+----+----+----+----+
| encrypted timestamp     (28 байт)
+----+----+----+----+
| MAC1                    (16 байт)
+----+----+----+----+
| MAC2                    (16 байт)
+----+----+----+----+
                          = 148 байт

HandshakeResponse — 92 байта, тоже фиксировано. CookieReply — 64 байта.

ТСПУ ловит это одним правилом:

match: udp.length == 148 AND payload[0] == 0x01 AND payload[1:4] == 0x000000
action: drop

Точность близкая к 100%, false positive стремится к нулю — в природе UDP-пакет такой формы статистически не встречается. Поэтому нативный WireGuard в РФ блокируется на первом же handshake’е.

Что добавляет AmneziaWG

AmneziaWG — модификация референсной реализации WireGuard, разработанная командой Amnezia (open-source, Go-форк amnezia-vpn/amneziawg-go). В неё добавлены семь параметров обфускации, которые ломают сигнатурный детект:

Jc, Jmin, Jmax — junk-пакеты

Jc — количество junk-пакетов случайной длины, которые клиент отправляет до реального HandshakeInitiation. Длина каждого junk-пакета — случайное число в диапазоне [Jmin, Jmax].

Например, при Jc=4, Jmin=50, Jmax=1000:

→ Junk #1: 234 байта  (мусор)
→ Junk #2: 871 байт   (мусор)
→ Junk #3: 102 байта  (мусор)
→ Junk #4: 612 байт   (мусор)
→ HandshakeInitiation: 148 байт + S1 + S2 (см. ниже)

ТСПУ ожидает увидеть 148-байтный пакет первым. А получает четыре пакета случайной длины — и пятый, который тоже не ровно 148 (см. далее). Сигнатура не срабатывает.

Почему ТСПУ не может «просто игнорировать первые N пакетов»: атака на stateful-фильтр. Если правило «дропать 148-байтные UDP-пакеты только если они первые в сессии», то достаточно отправить один мусорный байт перед хэндшейком — и протокол выживет. Если правило «дропать всегда» — это false positive на любой UDP/443 с такой длиной (а такие есть в QUIC, DTLS, etc).

S1, S2 — header padding в WG-пакете

S1 — количество случайных байт, добавляемых перед реальным header’ом WireGuard-пакета. S2 — количество случайных байт после header’а.

С учётом S1=15 и S2=23 (примерные дефолтные значения AmneziaVPN на 2026):

| 15 байт случайного мусора | type=1 | 0x000000 | sender index | ... | 23 байта мусора | MAC1 | MAC2 |

Итоговая длина — 148 + 15 + 23 = 186 байт. И эта длина рандомизирована параметрами — у каждого инстанса AmneziaWG свои S1/S2, генерируемые при настройке.

Что делает ТСПУ: видит UDP-пакет длиной 186 (или 173, или 201 — у каждого клиента своё). Этот пакет не подходит ни под сигнатуру WG, ни под сигнатуру OpenVPN, ни под QUIC. Классификатор не находит зацепки.

H1, H2, H3, H4 — packet magic в WG-фреймах

H1H4 — четыре байтовые константы, которые переписывают первые 4 байта в каждом из четырёх типов WG-пакетов:

  • H1 — заменяет тип 0x01 в HandshakeInitiation.
  • H2 — заменяет тип 0x02 в HandshakeResponse.
  • H3 — заменяет тип 0x03 в CookieReply.
  • H4 — заменяет тип 0x04 в TransportData (data-пакеты).

Зачем: даже если S1/S2 ломают длину, теоретически ТСПУ может ловить сигнатуру по «первый байт = 0x01, следующие 3 = 0x00». H1 ломает и это — после смены первый байт становится случайным значением, согласованным между клиентом и сервером.

Trade-off: H1–H4 нарушают совместимость со стандартным WireGuard. Клиент-AmneziaWG не сможет подключиться к серверу-нативному-WG. Поэтому обе стороны должны использовать AmneziaWG с одинаковыми H1–H4.

Пример вычислений длин

Конфигурация AmneziaVPN (упрощённо, реальные значения зашиты в клиент):

Jc = 4
Jmin = 50
Jmax = 1000
S1 = 50
S2 = 100
H1 = 1234567890
H2 = 2345678901
H3 = 3456789012
H4 = 4567890123

С этими параметрами при handshake’е по проводу идёт:

ПакетБез обфускации (нативный WG)AmneziaWG с указанной конфигурацией
Junk #1случайная длина 50–1000
Junk #2случайная длина 50–1000
Junk #3случайная длина 50–1000
Junk #4случайная длина 50–1000
HandshakeInitiation148 байт, тип 0x01298 байт (148+50+100), тип переписан H1
HandshakeResponse (от сервера)92 байта, тип 0x02242 байта (92+50+100), тип переписан H2

Никакой одной сигнатуры, которая ловит и нативный WG, и AmneziaWG, не существует. ТСПУ должен бы научиться видеть AmneziaWG-сигнатуру отдельно — но её сложно построить, потому что параметры варьируются от клиента к клиенту.

Чего AmneziaWG не делает

Важное ограничение, которое часто упускается в обзорах: AmneziaWG обфусцирует только handshake-фазу. Data-пакеты (TransportData) после установки сессии идут с теми же длинами, что и нативный WireGuard — фрейм MTU минус 32 байта overhead’а WG. Если ТСПУ применяет поведенческий анализ длин потока, AmneziaWG не защищает.

Что не закрыто:

  • Распределение длин data-пакетов. Нативный MTU = 1420 байт payload (стандарт WG). Длина каждого data-пакета почти всегда близка к этому максимуму при стриминге. На большой выборке ТСПУ видит «равномерный поток 1420-байтных UDP-пакетов» — это сильный маркер VPN.
  • Inter-arrival timing. Constant-rate шифрованный поток выдаёт VPN даже без анализа содержимого. См. DAITA — там как раз про это.
  • Объём сессии. Если пользователь гонит 100 GB через UDP/12345 в течение часа, это явно не «обычный пользователь интернета». Защита — только через CDN-маскировку (HTTP/3) или constant-rate padding.

Полную защиту даёт связка AmneziaWG (handshake) + shadow-tls на data (но это другая архитектура, требует прокси-сервера) либо VLESS Reality (TLS-маскировка по всему потоку).

Trade-off в реальном использовании

Overhead на инициацию. Junk-пакеты добавляют 200 байт – 4 KB к каждому handshake’у (зависит от Jc * (Jmin+Jmax)/2). Это разовый расход, происходит только при подключении. На bandwidth не сказывается.

Latency на подключение. Несколько лишних UDP-пакетов туда-сюда добавляют 30–80 ms к подключению (на хороший канал). Реальное замечание: на нестабильном соединении handshake может теряться, и retry даёт ещё +500 ms. Не критично для обычного использования, но заметно при частых переподключениях.

Совместимость. Клиент и сервер должны использовать одинаковые S1/S2/H1–H4. Это значит, что нельзя подключиться к стандартному WG-серверу AmneziaWG-клиентом и наоборот. В реальности это редкая проблема — провайдеры VPN, которые катят AmneziaWG, выкатывают оба конца сразу.

Сравнение с Reality — почему оба нужны

VLESS Reality — другой подход к обфускации. Не «спрятать handshake внутри случайного UDP-шума», а «сделать handshake идентичным TLS-обращению к легитимному сайту».

Принципиальные отличия:

КритерийAmneziaWGVLESS Reality
ТранспортUDP, нестандартный портTCP/443
Что маскируетсяДлины + magic bytes WG-handshake’аВесь TLS-handshake, включая SNI и сертификат
Имя в SNI— (нет TLS)Чужой публичный домен (microsoft.com)
СкоростьБлизка к нативному WG (быстрее)Slightly slower (TLS overhead)
Где работаетСтабильнее на МТС/МегаФонСтабильнее на Билайн/Т2 (subjective, наблюдение)
Контр-DPIЛомает сигнатуру по длине + magicМаскирует под чужой сайт

В реальности оба нужны. Серьёзные сервисы катят и тот, и другой — пользователь переключает в клиенте, когда один деградирует. Подробнее — в сравнении AmneziaWG vs WireGuard и пилларе про DPI-evolution.

Какие клиенты поддерживают AmneziaWG

  • AmneziaVPN — оригинальный клиент команды Amnezia. AmneziaWG включён по умолчанию, можно настроить параметры обфускации вручную.
  • Hiddify — поддерживает AmneziaWG как опцию (через встроенный AmneziaWG-Go).
  • AmneziaWG официальный клиент — упрощённый GUI для пользователей, которые не хотят возиться с настройкой Amnezia (только AmneziaWG-протокол, без UI вокруг).
  • wg-quick + amneziawg-tools — для тех, кто хочет CLI. Конфиг почти идентичен wg-quick, добавляются строки Jc, Jmin, Jmax, S1, S2, H1H4 в секцию [Interface].

На уровне серверов AmneziaWG поддерживают: AmneziaVPN-сервер (self-hosted), Outline (через адаптер), часть коммерческих провайдеров (AmneziaVPN Premium, Durev VPN, ряд других). Полный список — в каталоге протоколов.

Итог

  • WireGuard handshake — фиксированной длины (148/92/64 байта), ловится ТСПУ одним правилом за миллисекунды.
  • AmneziaWG добавляет семь параметров обфускации: Jc/Jmin/Jmax (junk-пакеты до handshake’а), S1/S2 (header padding в WG-пакете), H1–H4 (magic bytes четырёх типов пакетов).
  • Сигнатура нативного WG не срабатывает — длины рандомизированы, magic переписан, между ClientHello-эквивалентом летит несколько мусорных пакетов.
  • Не закрывает поведенческий анализ data-фазы — длины data-пакетов остаются как у нативного WG. Полная защита требует комбинации с другими техниками (VLESS Reality, DAITA, shadow-tls).
  • Trade-off минимальный — +30–80 ms на handshake, +200 байт – 4 KB на установку сессии. На bandwidth и latency steady-state не сказывается.

Связанные статьи

читать дальше

Похожие статьи