WireGuard — почему это новый стандарт

Когда Линус Торвальдс назвал WireGuard «произведением искусства» и принял в ядро Linux (5.6, март 2020) — индустрия признала: новый стандарт VPN. 4 000 строк кода против 600 000 у OpenVPN. Быстрее IPsec в 2 раза. Криптография намертво зашита, конфигурация — одна страница. Но у него есть критическая слабость для обхода блокировок.

Что узнаешь

1. Философия WireGuard: «opinionated» дизайн

Jason Donenfeld в 2015 сел и решил написать VPN с нуля, опираясь на современную криптографию и многолетний опыт боли OpenVPN/IPsec. Ключевые принципы:

  1. Один шифр, один key exchange, один MAC. Никакого согласования алгоритмов (как в TLS). Криптография зашита: Curve25519, ChaCha20-Poly1305, BLAKE2s. Не нравится — не используй WireGuard. Если завтра ChaCha20 сломают — выйдет WireGuard 2.0.
  2. UDP-only. Никакого TCP. TCP-over-TCP даёт «meltdown» при потерях.
  3. Stateless handshake. Сервер не помнит «полусоединения» — нет DoS-уязвимости.
  4. Crypto-routing. Адрес клиента в туннеле жёстко привязан к его публичному ключу в конфиге (AllowedIPs). Не угадаешь IP — не подменишь.
  5. Stealth. Сервер не отвечает на левые пакеты вообще. Без знания ключа — порт «закрыт».
  6. Конфигурация — текстовый файл на 10 строк. Не XML, не GUI, не базу.

2. Криптопримитивы — почему именно эти

ЗадачаАлгоритмПочему
Key exchangeCurve25519 (X25519)Быстрый ECDH, без слабых параметров (привет, P-curves NSA)
Симметричное шифрованиеChaCha20Быстрее AES на ARM (мобильники), без cache-timing атак
Аутентификация (AEAD)Poly1305Идёт в паре с ChaCha20, стандарт от Bernstein
Хэш / KDF / MACBLAKE2sБыстрее SHA-2, безопасно использовать как PRF
HKDFHKDF(BLAKE2s)Стандартное KDF из RFC 5869
Под капотом

Почему «принцип одного шифра» — это сила, а не слабость

В TLS/IPsec клиент и сервер согласовывают шифры. Это создаёт downgrade-атаки: MITM меняет ClientHello и заставляет согласиться на слабый шифр. Все BEAST, POODLE, FREAK, Logjam — об этом.

В WireGuard согласовывать нечего. Поддерживаемый шифр один. Атаки на согласование невозможны математически. Это редкий случай в безопасности, когда жёсткое ограничение — преимущество.

3. Noise_IK handshake — 4 сообщения

WireGuard использует паттерн Noise_IK из Noise Framework (см. урок 02). 4 сообщения: Initiation, Response, далее уже data. Каждое — фиксированной длины.

WireGuard handshake побайтово
Initiator Responder ① Handshake Initiation (148 байт) type = 1 (1 byte) reserved (3 bytes) sender_index (4 bytes) unencrypted_ephemeral (32 bytes) — pub_e_i encrypted_static (32+16) — шифр(pub_s_i) ② Handshake Response (92 байта) type = 2 (1 byte) sender + receiver indexes (8 bytes) unencrypted_ephemeral (32 bytes) — pub_e_r encrypted_nothing (0+16 байт MAC) ③ Data packets — ChaCha20-Poly1305
Всего 2 пакета handshake и через 100 мс канал готов. Контрастно с TLS 1.3 (3-4 пакета).

Сообщение 1 — Handshake Initiation побайтово

0000 01 type = 1 (initiation) ← DPI читает первым 0001 00 00 00 reserved = 0 0004 a3 4f 91 b2 sender_index = random uint32 0008 [32 bytes: pub_e_i] ephemeral X25519 публичный ключ инициатора 0028 [32+16 bytes] зашифрованный статический ключ инициатора + tag 0058 [12+16 bytes] зашифрованный timestamp (TAI64N) для anti-replay + tag 0080 [16 bytes: mac1] MAC = MAC(MAC1_KEY, payload), MAC1_KEY = BLAKE2s("mac1--", pub_s_r) 0090 [16 bytes: mac2] cookie-MAC (см. ниже)
КРИТИЧЕСКАЯ ПРОБЛЕМА 2026

Первый байт всегда 0x01

Длина пакета — всегда 148 байт. Первый байт — всегда 0x01. Это идеальная сигнатура для DPI. Правило ТСПУ выглядит примерно так:

match: udp.length == 148 AND udp.payload[0] == 0x01
       AND udp.payload[1..4] == 0x000000
       AND udp.payload[8..40] looks like X25519 point
action: drop, blacklist src_ip for 60s
    

Поэтому WireGuard на дефолтных настройках режут в России c 2023. И в Иране, и в Китае. Канал поднимается, через 30 секунд handshake перестаёт проходить.

Сервер делает дорогое X25519-вычисление при каждой Initiation. Атакующий мог бы засыпать сервер фальшивыми Initiation — сервер тратил бы CPU. Решение: cookie-reply.

Если сервер под нагрузкой — на следующую Initiation от данного IP он отвечает не Response, а специальным cookie-пакетом (type=3). Cookie — это hmac(secret, client_ip), валиден 2 минуты. Клиент должен включить cookie в mac2 следующей Initiation.

Эффект

Атакующий с подделанным src_ip не получит cookie (ответ пойдёт на жертву, не атакующему). Без cookie сервер не делает дорогих DH-вычислений. Атака на CPU не работает.

5. Data-пакет побайтово

После handshake клиент и сервер обмениваются Transport Data packets:

0000 04 type = 4 (Transport Data) 0001 00 00 00 reserved 0004 b1 22 9c 4f receiver_index (полученный от противоположной стороны) 0008 00 00 00 00 01 23 4f 89 counter (64-bit, ChaCha20 nonce) 0010 [N bytes: encrypted_packet + 16 bytes Poly1305] зашифрованный IP-пакет + tag

Длина зашифрованного пакета = длина оригинального IP-пакета + 16 байт (auth tag) + дополнения до 16-байтового выравнивания (padding). Overhead самого WireGuard над исходным IP-пакетом: 16 (data-header) + 16 (tag) = 32 байта. С учётом внешнего IPv4 (20) и UDP (8) полный overhead туннеля — ≈ 60 байт (поэтому типичный MTU интерфейса WireGuard — 1420).

6. Реализации: kernel vs userspace

РеализацияГдеПроизводительностьЗачем
kernel moduleLinux 5.6+, FreeBSD 13.2+, OpenBSD10+ Гбит/с на ядроПродакшн на серверах
wireguard-gomacOS, Windows, любой OS1-2 Гбит/сКроссплатформа референсная
BoringTun (Rust)Cloudflare, embedded2-4 Гбит/сБезопасность памяти (Rust)
kmod на роутерахOpenWRT, Mikrotik 7.x, Asuswrt-Merlinзависит от железаДомашние/SOHO
Под капотом

Почему kernel так быстро

В user-space реализации (OpenVPN, wireguard-go) пакет проходит: kernel → tun → userspace → шифр → userspace → udp → kernel. 4 переключения контекста на пакет.

Kernel-module делает всё в одном context: получил пакет → расшифровал → передал в стек. В разы быстрее. Плюс ChaCha20-Poly1305 в Linux 5.6+ векторизованный (AVX-512).

7. Минимальная конфигурация

Серверная сторона /etc/wireguard/wg0.conf:

[Interface]
PrivateKey = SERVER_PRIV_KEY_BASE64       # ← wg genkey
Address    = 10.8.0.1/24                  # внутренний IP туннеля
ListenPort = 51820                        # UDP-порт (любой)
PostUp     = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown   = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
PublicKey  = CLIENT_PUB_KEY_BASE64        # ← клиент сообщает свой публичный ключ
AllowedIPs = 10.8.0.2/32                  # какие IP пропускать «как от этого клиента»
  

Клиентская сторона:

[Interface]
PrivateKey = CLIENT_PRIV_KEY_BASE64
Address    = 10.8.0.2/24
DNS        = 1.1.1.1, 1.0.0.1            # DNS внутри туннеля (необязательно)

[Peer]
PublicKey  = SERVER_PUB_KEY_BASE64
Endpoint   = vpn.example.com:51820        # IP/домен сервера
AllowedIPs = 0.0.0.0/0, ::/0              # «весь трафик в туннель»
PersistentKeepalive = 25                  # каждые 25с пинг, чтобы NAT не закрыл маппинг
  

Всё. Стартуем: sudo wg-quick up wg0. Никаких XML, GUI, БД.

8. AmneziaWG — российский ответ на детект

Российская команда AmneziaVPN доработала WireGuard, чтобы обойти проблему «первый байт всегда 0x01 / длина всегда 148». Идея — добавить junk-пакеты и обфускацию.

Контрмеры в AmneziaWG
  1. Jc / Jmin / Jmax: сразу после соединения клиент шлёт несколько мусорных пакетов случайной длины — DPI видит «много байт непонятно чего», не похожих на WG.
  2. S1 / S2: к каждому обычному пакету добавляется случайный prefix-byte и postfix-byte. Длина пакета перестаёт быть «148 байт».
  3. H1 / H2 / H3 / H4: магические заголовки заменяются на конфигурируемые значения. Первый байт уже НЕ 0x01.

В результате трафик AmneziaWG неотличим от случайного UDP-шума. ТСПУ перестаёт детектить «по сигнатуре». В 2024-2025 это активно работает в РФ.

Минус

ML-классификация всё ещё может зацепить

ТСПУ может смотреть не только на байты, но и на статистику пакетов (тайминги, размеры, корреляция). AmneziaWG ломает байтовый fingerprint, но не статистический. Поэтому будущее — за более радикальной маскировкой (Reality, ECH). AmneziaWG — отличное tactical решение, но не «защита навсегда».

9. Итог

  1. WireGuard — лучший VPN для скорости и простоты. Если задача — корпоративный remote-access, site-to-site без DPI, домашняя приватность — WG победил всех.
  2. В странах с активным DPI голый WireGuard не работает: 0x01 + 148 байт = жалоба ТСПУ.
  3. AmneziaWG закрывает байтовую сигнатуру, но не статистическую — это решение на год-два, пока DPI не нагонит.
  4. Для обхода продвинутых блокировок WireGuard не годится в чистом виде. Нужна обёртка (Reality, Shadowsocks-as-proxy + WG внутри) или другой протокол.
  5. Знать WireGuard обязательно — это базовый VPN в любой корпоративной/домашней инфре.

В следующем уроке — модель противника. Что такое DPI, как он работает, что видит: JA3/JA4, ALPN-fingerprinting, active probing. Без этой модели бессмысленно говорить об обходе блокировок — сначала нужно понять, что именно ищет ТСПУ/GFW и по каким признакам отличает VPN-трафик от обычного.