WireGuard — почему это новый стандарт
Когда Линус Торвальдс назвал WireGuard «произведением искусства» и принял в ядро Linux (5.6, март 2020) — индустрия признала: новый стандарт VPN. 4 000 строк кода против 600 000 у OpenVPN. Быстрее IPsec в 2 раза. Криптография намертво зашита, конфигурация — одна страница. Но у него есть критическая слабость для обхода блокировок.
- Почему WireGuard такой маленький и быстрый — главные дизайн-решения
- Криптография: Curve25519 + ChaCha20-Poly1305 + Poly1305 + BLAKE2s — почему именно эти
- Noise_IK handshake побайтово: 4 сообщения, 32+16 байт каждое
- Формат пакета данных побайтово
- Cookie-anti-DoS — защита сервера от лавины подделанных handshake
- Kernel module vs
wireguard-govsboringtun - Главная слабость 2026: детектится первым байтом
- AmneziaWG — российский ответ на эту слабость
Всё, что нужно, уже разобрано: Noise Framework и обмен ключами X25519 — урок 2 (WireGuard — это Noise_IK в чистом виде); слабости классики (фиксированные порты, узнаваемые рукопожатия) — урок 3, и WireGuard бьёт их размером кода и скоростью; но «форму» из аналогии урока 3 он не прячет — отсюда его слабость к DPI, которую здесь и разберём.
1. Философия WireGuard: «opinionated» дизайн
Jason Donenfeld в 2015 сел и решил написать VPN с нуля, опираясь на современную криптографию и многолетний опыт боли OpenVPN/IPsec. Ключевые принципы:
- Один шифр, один key exchange, один MAC. Никакого согласования алгоритмов (как в TLS). Криптография зашита: Curve25519, ChaCha20-Poly1305, BLAKE2s. Не нравится — не используй WireGuard. Если завтра ChaCha20 сломают — выйдет WireGuard 2.0.
- UDP-only. Никакого TCP. TCP-over-TCP даёт «meltdown» при потерях.
- Stateless handshake. Сервер не помнит «полусоединения» — нет DoS-уязвимости.
- Crypto-routing. Адрес клиента в туннеле жёстко привязан к его публичному ключу в конфиге (AllowedIPs). Не угадаешь IP — не подменишь.
- Stealth. Сервер не отвечает на левые пакеты вообще. Без знания ключа — порт «закрыт».
- Конфигурация — текстовый файл на 10 строк. Не XML, не GUI, не базу.
2. Криптопримитивы — почему именно эти
| Задача | Алгоритм | Почему |
|---|---|---|
| Key exchange | Curve25519 (X25519) | Быстрый ECDH, без слабых параметров (привет, P-curves NSA) |
| Симметричное шифрование | ChaCha20 | Быстрее AES на ARM (мобильники), без cache-timing атак |
| Аутентификация (AEAD) | Poly1305 | Идёт в паре с ChaCha20, стандарт от Bernstein |
| Хэш / KDF / MAC | BLAKE2s | Быстрее SHA-2, безопасно использовать как PRF |
| HKDF | HKDF(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. Каждое — фиксированной длины.
Сообщение 1 — Handshake Initiation побайтово
Первый байт всегда 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 перестаёт проходить.
4. Cookie reply — защита от DoS
Сервер делает дорогое 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:
Длина зашифрованного пакета = длина оригинального 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 module | Linux 5.6+, FreeBSD 13.2+, OpenBSD | 10+ Гбит/с на ядро | Продакшн на серверах |
| wireguard-go | macOS, Windows, любой OS | 1-2 Гбит/с | Кроссплатформа референсная |
| BoringTun (Rust) | Cloudflare, embedded | 2-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, БД.
AllowedIPs — это одновременно «белый список» и «карта маршрутов»
Самое непонятное для новичка поле AllowedIPs носит две шляпы сразу. На стороне
сервера в секции [Peer] это пропуск: «пакеты с внутренним адресом
10.8.0.2 — законны только от этого клиента, чужие отбрось» (криптомаршрутизация: адрес привязан
к публичному ключу). На стороне клиента AllowedIPs = 0.0.0.0/0 — это уже
маршрут: «весь трафик заворачивай в туннель». Одно и то же поле: у сервера —
«кому верю», у клиента — «что отправляю». Отсюда 90% ошибок конфигурации новичков.
8. Мини-лаба: попробуй прямо сейчас
Поднять настоящий туннель нужен root и сервер, но ключи и интерфейс WireGuard
можно пощупать локально за пару минут — установи пакет wireguard-tools:
# 1. Сгенерируй пару ключей — как в разделе 7. Это X25519 из урока 2
wg genkey | tee priv.key | wg pubkey > pub.key
cat priv.key # приватный — секрет
cat pub.key # публичный — отдаёшь серверу
# 2. Если есть права root — подними пустой интерфейс и посмотри его
sudo ip link add dev wg-test type wireguard
sudo wg set wg-test private-key ./priv.key listen-port 51820
sudo ip addr add 10.9.0.1/24 dev wg-test
sudo ip link set wg-test up
ip a show wg-test # вот он — тот самый виртуальный интерфейс из урока 1!
sudo wg show wg-test # public key, порт, пиры (пока пусто)
# 3. Прибери за собой
sudo ip link del wg-test
# 4. Нет root? Хотя бы посмотри, детектируем ли WG «по форме» —
# handshake WG всегда начинается с байта 0x01 и имеет длину 148 байт.
# Именно это и ищет ТСПУ. Убедись, почему раздел 8 (AmneziaWG) необходим.
В пункте 1 получишь пару base64-ключей — это ровно то, что в конфиге стоит в PrivateKey/PublicKey.
В пункте 2 (если есть root) ip a покажет новый интерфейс wg-test со
«своим» IP 10.9.0.1 и без физического кабеля — материализация «виртуальной сети» из урока 1, а
wg show выведет публичный ключ и порт. Запомни: это тот же список интерфейсов, что
ты смотрел в лабе урока 1 — теперь в нём появился туннельный. Реальный обмен трафиком добавит
сюда пира и строку «latest handshake».
9. AmneziaWG — российский ответ на детект
Российская команда AmneziaVPN доработала WireGuard, чтобы обойти проблему «первый байт всегда 0x01 / длина всегда 148». Идея — добавить junk-пакеты и обфускацию.
- Jc / Jmin / Jmax: сразу после соединения клиент шлёт несколько мусорных пакетов случайной длины — DPI видит «много байт непонятно чего», не похожих на WG.
- S1 / S2: к каждому обычному пакету добавляется случайный prefix-byte и postfix-byte. Длина пакета перестаёт быть «148 байт».
- H1 / H2 / H3 / H4: магические заголовки заменяются на конфигурируемые значения. Первый байт уже НЕ 0x01.
В результате трафик AmneziaWG неотличим от случайного UDP-шума. ТСПУ перестаёт детектить «по сигнатуре». В 2024-2025 это активно работает в РФ.
ML-классификация всё ещё может зацепить
ТСПУ может смотреть не только на байты, но и на статистику пакетов (тайминги, размеры, корреляция). AmneziaWG ломает байтовый fingerprint, но не статистический. Поэтому будущее — за более радикальной маскировкой (Reality, ECH). AmneziaWG — отличное tactical решение, но не «защита навсегда».
10. Задачи самопроверки — реши, потом раскрой ответ
Задача 1. Клиент подключился, handshake прошёл, но интернета нет — пингуется только 10.8.0.1. В клиентском конфиге AllowedIPs = 10.8.0.0/24. Что не так?
AllowedIPs на клиенте — это маршруты «что заворачивать в туннель». С 10.8.0.0/24 в туннель уходит только трафик к внутренней подсети, а весь остальной интернет идёт мимо. Для «весь трафик через VPN» нужно AllowedIPs = 0.0.0.0/0, ::/0. Плюс на сервере должен быть включён форвардинг и NAT (MASQUERADE) — иначе завёрнутый трафик не выйдет наружу.
Задача 2. WireGuard быстрее OpenVPN и IPsec в разы при меньшем коде. За счёт каких двух дизайн-решений — и что это решение «стоило»?
(1) Жёстко зашитый набор криптопримитивов (Curve25519, ChaCha20-Poly1305, BLAKE2s) — нет согласования шифров, нет legacy-веток, меньше кода и уязвимостей, работа в ядре без переключений контекста. (2) Минимализм модели: stateless-подход, криптомаршрутизация вместо тяжёлой логики. Цена — отсутствие гибкости (нельзя сменить шифр) и, главное, отсутствие маскировки: узнаваемый handshake, из-за которого голый WG блокируется DPI.
Задача 3. Мобильный клиент за NAT через минуту простоя «отваливается» — сервер перестаёт его видеть. Какая настройка это чинит и почему проблема именно на стороне клиента за NAT?
PersistentKeepalive = 25: клиент каждые 25 секунд шлёт пустой пакет, чтобы NAT-маппинг на роутере не протух. WireGuard по своей природе «молчит», когда нет трафика — а NAT закрывает неиспользуемую запись через 30–120 с, и сервер больше не знает, куда слать ответ (у него нет постоянного адреса клиента за NAT). Keepalive держит «дырку» открытой. На сервере с публичным IP это не нужно.
Задача 4. В стране с активным DPI голый WireGuard живёт несколько минут и умирает, хотя криптографию никто не сломал. Что именно детектит ТСПУ и как AmneziaWG это ломает?
Детект по сигнатуре: handshake-инициация WG всегда начинается с байта 0x01 (тип сообщения) и имеет фиксированную длину 148 байт — это опознаётся без расшифровки, одним правилом. AmneziaWG ломает байтовый отпечаток: junk-пакеты случайной длины в начале (Jc/Jmin/Jmax), случайные префикс/постфикс-байты (S1/S2) и заменяемые магические заголовки (H1–H4) — первый байт больше не 0x01, длина не 148. Оговорка: статистический/ML-детект по таймингам это не закрывает.
Задача 5. Для домашней приватности и объединения серверов в датацентрах коллега предлагает WireGuard, для обхода блокировок в цензурируемой стране — тоже WireGuard. Где он прав, а где нет?
Прав в первом: для remote-access, site-to-site и mesh без враждебного DPI WireGuard — лучший выбор (скорость, простота, стойкость). Неправ во втором: там, где DPI целенаправленно ищет VPN, голый WG опознаётся по сигнатуре и блокируется. Нужен либо AmneziaWG (тактически), либо маскировка под HTTPS (Reality) — WG при этом может ехать ВНУТРИ такой обёртки. Инструмент выбирается по угрозе-модели, а не по привычке.
11. Словарик урока
12. Итог
- WireGuard — лучший VPN для скорости и простоты. Если задача — корпоративный remote-access, site-to-site без DPI, домашняя приватность — WG победил всех.
- В странах с активным DPI голый WireGuard не работает: 0x01 + 148 байт = жалоба ТСПУ.
- AmneziaWG закрывает байтовую сигнатуру, но не статистическую — это решение на год-два, пока DPI не нагонит.
- Для обхода продвинутых блокировок WireGuard не годится в чистом виде. Нужна обёртка (Reality, Shadowsocks-as-proxy + WG внутри) или другой протокол.
- Знать WireGuard обязательно — это базовый VPN в любой корпоративной/домашней инфре.
В следующем уроке — модель противника. Что такое DPI, как он работает, что видит: JA3/JA4, ALPN-fingerprinting, active probing. Без этой модели бессмысленно говорить об обходе блокировок — сначала нужно понять, что именно ищет ТСПУ/GFW и по каким признакам отличает VPN-трафик от обычного.