Как работает фингерпринтинг HTTP/3 и QUIC: транспортные параметры в пакете QUIC Initial, сигнал h3 ALPN и отличия от HTTP/2-фингерпринтинга.
HTTP/2-фингерпринтинг читает фрейм SETTINGS, прирост окна и порядок псевдозаголовков, которые клиент отправляет по TCP+TLS. HTTP/3 сворачивает то же самое рукопожатие в единый транспорт на основе UDP — QUIC, — и при этом часть сигналов перемещается в новое место, часть сливается с уровнем TLS, а один сигнал исчезает вовсе. В результате получается отпечаток, который пересекается с TLS-фингерпринтингом сильнее, чем это было у HTTP/2, но не идентичен ему.
Ключевые выводы
- QUIC объединяет транспортное и TLS-рукопожатие в один раунд обмена. Первый UDP-пакет, который отправляет QUIC-клиент — Initial-пакет — несёт TLS 1.3 ClientHello, поэтому всё, что JA3/JA4 читают из ClientHello по TCP, присутствует и здесь.
- Транспортные параметры QUIC — новый, специфичный для протокола сигнал. Они передаются внутри ClientHello как TLS-расширение
quic_transport_parameters(RFC 9001) и раскрывают специфичные для реализации значения — такие как начальные лимиты управления потоком и длина идентификатора соединения, — не имеющие аналога в HTTP/2. - JA4 уже учитывает QUIC. Первый символ отпечатка указывает на транспорт, по которому пришло соединение:
qдля QUIC,tдля TCP,dдля DTLS — см. спецификацию JA4. Отпечаток видаq13d...напрямую сопоставим сt13d...от того же клиента по TCP. - Собственный фрейм SETTINGS у HTTP/3 гораздо тоньше, чем у HTTP/2, а фреймы PRIORITY исчезли вовсе — их заменила схема расширяемых приоритетов на основе заголовка, которую большинство клиентов вообще не отправляют.
- Значение ALPN
h3— самый ранний сигнал прикладного уровня: оно появляется в том же расширении ClientHello, что иh2для HTTP/2, только теперь передаётся через QUIC, а не TCP.
Почему QUIC меняет картину фингерпринтинга
HTTP/2-фингерпринтинг существует потому, что TCP и TLS — отдельные протоколы: сначала TCP-рукопожатие устанавливает соединение, затем TLS ClientHello согласовывает шифрование, а уже после завершения TLS клиент отправляет собственные стартовые фреймы HTTP/2 (SETTINGS, WINDOW_UPDATE, PRIORITY). Три уровня — три возможности снять отпечаток.
QUIC (RFC 9000) — транспорт на основе UDP, который сворачивает установку соединения и шифрование в единый обмен. Его первый пакет — Initial-пакет — несёт полноценный TLS 1.3 ClientHello внутри фрейма CRYPTO, интегрированный прямо в транспортное рукопожатие (RFC 9001), а не надстроенный поверх него, как раньше. HTTP/3 (RFC 9114) затем работает поверх уже установленного QUIC-соединения, широко переиспользуя то, что уже предоставляет сам QUIC — мультиплексирование потоков и управление потоком, — вместо того чтобы заново определять их, как это делал HTTP/2 для TCP.
Такая реструктуризация означает, что QUIC-клиент раскрывает:
- TLS 1.3 ClientHello, отправленный внутри Initial-пакета — те же наборы шифров, расширения и значение ALPN, которые JA3/JA4 уже фингерпринтят по TCP.
- Транспортные параметры QUIC — новое TLS-расширение, уникальное для этого рукопожатия.
- Гораздо меньший фрейм SETTINGS HTTP/3, отправляемый по однонаправленному управляющему потоку после установления соединения.
Транспортные параметры QUIC: новый сигнал
Каждый QUIC-клиент обязан отправить в своём ClientHello расширение quic_transport_parameters (кодовая точка 0x39), объявляя такие значения, как initial_max_data, initial_max_stream_data, max_idle_timeout и active_connection_id_limit. Эти параметры описывают ограничения соединения, которые клиент готов поддерживать, — и, как и значения SETTINGS в HTTP/2, конкретные значения по умолчанию, выбранные реализацией, различаются между QUIC-библиотеками.
QUIC-стек Chrome, neqo от Firefox, quiche (используемый curl и Cloudflare), msquic и ngtcp2 — у каждого свои параметры транспорта по умолчанию. Поскольку это расширение находится внутри того же ClientHello, который JA3/JA4 уже хешируют, серверу для фингерпринтинга не нужен отдельный механизм сбора данных — достаточно разобрать это одно дополнительное расширение в уже читаемом пакете.
JA4 уже умеет говорить на языке QUIC
TLS-фингерпринтингу не потребовался новый алгоритм для QUIC — потребовалось лишь одно дополнительное поле. Спецификация JA4 кодирует наблюдаемый транспорт в самом первом символе отпечатка: q для QUIC, d для DTLS, t для обычного TLS поверх TCP. Всё, что идёт после этого символа — версия TLS, хеш шифров и хеш расширений — вычисляется абсолютно так же независимо от транспорта, потому что читается та же самая структура ClientHello.
Это имеет практическое следствие: серверу, уже проверяющему JA4 для TLS-фингерпринтинга, не нужна никакая новая логика для фингерпринтинга QUIC-соединений. Он автоматически получает отпечаток вида q13d... и может напрямую сравнить его с отпечатком t13d..., который тот же браузер производит по обычному TLS, — несовпадение в хешированных частях между TCP- и QUIC-отпечатками одного клиента само по себе сигнал, заслуживающий проверки.
Более тонкий фрейм SETTINGS у HTTP/3
Собственный фрейм SETTINGS HTTP/3 (RFC 9114 §7.2.4) определяет на уровне HTTP только SETTINGS_MAX_FIELD_SECTION_SIZE. Ещё два параметра — SETTINGS_QPACK_MAX_TABLE_CAPACITY и SETTINGS_QPACK_BLOCKED_STREAMS — приходят из QPACK, схемы сжатия полей HTTP/3 (переработки HPACK от HTTP/2 для доставки не по порядку), и определены отдельно. По сравнению с шестью стандартными параметрами SETTINGS у HTTP/2 плюс фреймом WINDOW_UPDATE, это гораздо меньшая поверхность: сам QUIC уже обрабатывает управление потоком и лимиты потоков на транспортном уровне через описанные выше транспортные параметры, поэтому HTTP/3 не нужно заново согласовывать их на прикладном уровне, как это делал HTTP/2 поверх обычного TCP.
Фреймов PRIORITY больше нет
У фреймов PRIORITY из HTTP/2 — уже упразднённых RFC 9113 — нет вообще никакого аналога в базовом наборе фреймов HTTP/3. Приоритизация потоков переместилась в схему расширяемых приоритетов, которая сигнализирует срочность через HTTP-заголовок Priority (или эквивалентный фрейм), а не через выделенный бинарный фрейм в начале соединения. Многие клиенты вообще не отправляют явных сигналов приоритета, полагаясь на настройки сервера по умолчанию, — это убирает то, что раньше было одним из самых характерных полей в более ранних работах по HTTP/2-фингерпринтингу.
Чем это отличается от HTTP/2-фингерпринтинга
| Сигнал | HTTP/2 (по TCP+TLS) | HTTP/3 (по QUIC) |
|---|---|---|
| TLS ClientHello | Отдельное TCP- и TLS-рукопожатие | Встроен в пакет QUIC Initial |
| Параметры транспортного уровня | Отсутствуют (у TCP нет аналога) | Расширение quic_transport_parameters |
| Фрейм SETTINGS | 6 стандартных параметров | 1 параметр HTTP + 2 параметра QPACK |
| Приоритет потоков | Фреймы PRIORITY (упразднены) | Заголовок расширяемых приоритетов, часто не задан |
| Значение ALPN | h2 | h3 |
| Применимость JA3/JA4 | Прямая (TLS поверх TCP) | Прямая, с маркером транспорта q |
Практический вывод: фингерпринтинг HTTP/3 сильнее опирается на уровень TLS, чем это делал HTTP/2-фингерпринтинг, потому что QUIC поглотил большинство из того, что раньше было отдельными шагами согласования транспорта, в тот же самый ClientHello, который уже читают JA3/JA4.
Применение в обнаружении ботов и VPN
У систем обнаружения есть конкретная причина интересоваться QUIC-фингерпринтингом: растущая доля браузерного трафика к Google, к сайтам за Cloudflare и к другим ранним внедрителям HTTP/3 теперь по умолчанию идёт по QUIC, а не по TCP. Фреймворк для ботов, построенный вокруг подделки TLS-рукопожатия по TCP, вообще не порождает QUIC-трафика — и это само по себе показательно, поскольку настоящий экземпляр Chrome, посещающий источник с поддержкой HTTP/3, как правило, согласовывает именно QUIC, а не откатывается на TCP. И наоборот, инструментарий, который действительно говорит на QUIC (через привязки к quiche или msquic), всё равно несёт параметры транспорта и настройки QPACK по умолчанию для этой библиотеки — отличимые от стека настоящего браузера без quiche точно так же, как поддельный HTTP/2-клиент выдаёт себя значениями SETTINGS.
Для обнаружения VPN и прокси QUIC добавляет нюанс: поскольку он работает поверх UDP, некоторые корпоративные фаерволы и устаревшие промежуточные устройства блокируют его полностью, вынуждая клиента откатываться на HTTP/2 по TCP. Этот паттерн отката — клиент, чей User-Agent заявляет о версии Chrome с поддержкой QUIC, но который никогда не согласовывает h3 — сам по себе наблюдаемый сигнал, отдельный от содержимого самого отпечатка.
Описанные здесь транспортные отпечатки QUIC и TLS снимаются на стороне сервера, поэтому они не доступны JavaScript на странице — но они работают вместе с клиентскими сигналами, которые система обнаружения считывает из вашего браузера. Эти сигналы можно увидеть на себе с помощью инструмента обнаружения ботов от BrowserInsight: он показывает состояние navigator.webdriver, следы headless-режима и автоматизации, а также согласованность отпечатка — каждый пункт с понятным объяснением и полностью вычисляется на стороне клиента.
Часто задаваемые вопросы
Нужен ли мне новый инструмент, чтобы увидеть свой QUIC-отпечаток?
Концептуально нет — любая серверная реализация JA4 уже производит его, поскольку ClientHello в QUIC разбирается так же, как и в TLS поверх TCP. Меняется место, где происходит захват пакетов: QUIC приходит по UDP, поэтому сервер или промежуточное устройство, рассчитанное только на инспекцию TCP-потоков, не увидит его без отдельного захвата UDP.
Может ли бот избежать QUIC-фингерпринтинга, отказавшись от HTTP/3?
Отчасти, но это обмен одного сигнала на другой. Откат к HTTP/2 избавляет от фингерпринтинга, специфичного для QUIC, но настоящий современный браузер, посещающий сайт с поддержкой HTTP/3, обычно как раз согласовывает QUIC — так что клиент, который последовательно избегает его, заявляя при этом об актуальной версии Chrome или Firefox, сам по себе аномалия, заслуживающая внимания.
Скрывает ли эти сигналы шифрование QUIC-рукопожатия, например ECH?
Encrypted Client Hello скрывает чувствительные поля внутреннего ClientHello (например, SNI) от наблюдателя в сети, но сервер назначения — который расшифровывает рукопожатие, чтобы обслужить соединение, — по-прежнему видит полный ClientHello, транспортные параметры и SETTINGS HTTP/3. ECH меняет то, что видит пассивный наблюдатель сети между клиентом и сервером; он не меняет то, что способен зафиксировать сам сервер источника.
Насколько зрел фингерпринтинг HTTP/3 по сравнению с HTTP/2?
Пока менее зрел — в основном потому, что внедрение QUIC, хотя и существенное у ряда крупных операторов, всё ещё меньше повсеместного TCP+TLS. По мере того как всё больше источников и CDN начинают терминировать HTTP/3 по умолчанию, стоит ожидать, что фингерпринтинг с учётом QUIC станет такой же стандартной частью стека обнаружения ботов, как уже стали JA3/JA4 и отпечаток Akamai.


