← Назад в базу знаний

HTTP/2 fingerprint: как антифрод вскрывает прокси через настройки протокола

HTTP/2 fingerprint: как антифрод вскрывает прокси через настройки протокола

HTTP/2 принёс скорость. И принёс новую головную боль для тех, кто прячется за прокси. Антифрод-системы научились снимать отпечатки пальцев с HTTP/2 соединений. И снимают их хреново для нас.

Почему HTTP/1.1 больше не катит

Старый добрый HTTP/1.1 — это текстовый протокол. Заголовки передаются как есть, в открытую. Fingerprint по нему — гадание на кофейной гуще. User-Agent подменил — и порядок.

HTTP/2 — бинарный. Он использует HPACK для сжатия заголовков, фреймы с конкретными флагами, WINDOW_UPDATE для управления потоком. Каждый клиент реализует это по-своему. Браузеры — одним способом, curl — другим, ваш кастомный прокси-скрипт — третьим.

Разница заметна сразу. Антифрод это видит.

HPACK: динамическая таблица как отпечаток

HPACK сжимает заголовки через две таблицы — статическую и динамическую. Статическая — это 61 запись, прописанная в RFC 7541. Динамическая — создаётся в процессе соединения.

Браузеры управляют динамической таблицей агрессивно. Они добавляют туда часто используемые заголовки, индексируют их. Прокси-клиенты — нет. Они либо вообще не используют динамическую таблицу, либо делают это коряво.

Пример. Chrome отправляет `:method: GET` как индекс 2 из статической таблицы. А ваш самописный прокси-скрипт на Python может отправить это как литерал. Размер пакета — разный. Время обработки — разное. Антифрод видит несоответствие.

```bash

Смотрим, что отправляет curl с HTTP/2

curl -v --http2 https://example.com 2>&1 | grep -E "HTTP/2|h2"

```

Если видите там только `HEADERS` и `DATA` без динамического сжатия — вы под колпаком.

SETTINGS: конфигурация, которую нельзя скрыть

Каждое HTTP/2 соединение начинается с обмена SETTINGS фреймами. Клиент говорит серверу: "Я могу принять столько-то потоков, мой максимальный размер фрейма — вот такой, я поддерживаю HPACK с размером таблицы N".

Браузеры отправляют строго определённые наборы параметров. Chrome, Firefox, Safari — у каждого своя сигнатура.

| Параметр SETTINGS | Chrome 120 | Firefox 121 | curl 8.4 |

|-------------------|------------|-------------|----------|

| SETTINGS_HEADER_TABLE_SIZE | 65536 | 65536 | 4096 |

| SETTINGS_MAX_CONCURRENT_STREAMS | 100 | 100 | 100 |

| SETTINGS_INITIAL_WINDOW_SIZE | 6291456 | 131072 | 65535 |

| SETTINGS_MAX_FRAME_SIZE | 16384 | 16384 | 16384 |

| SETTINGS_MAX_HEADER_LIST_SIZE | 262144 | 262144 | 262144 |

Смотрите на цифры. curl использует размер начального окна 65535. Chrome — 6291456. Это не случайно. Это часть отпечатка.

Прокси-серверы типа Squid или HAProxy часто передают настройки, характерные для серверного ПО, а не для браузера. Например, `SETTINGS_MAX_CONCURRENT_STREAMS` в 1000 вместо 100. Или вообще не отправляют SETTINGS фреймы в нужном порядке.

WINDOW_UPDATE: управление потоком выдаёт реализацию

WINDOW_UPDATE — механизм контроля перегрузки. Клиент говорит серверу: "Я обработал N байт, шли ещё". Реализации различаются по размеру окна и частоте обновлений.

Браузеры обновляют окно маленькими порциями. Каждые 16-32 КБ данных. Прокси-клиенты — большими. Или не обновляют вообще, пока не кончится буфер.

```python

import socket

import h2.connection

conn = h2.connection.H2Connection()

conn.initiate_connection()

Браузер обновляет окно каждые 16 КБ

Прокси-скрипт может сделать так:

conn.update_settings({

'INITIAL_WINDOW_SIZE': 1048576 # 1 МБ — подозрительно много

})

```

Размер окна в 1 МБ — красный флаг. Браузеры так не делают. Они экономят память.

PING фреймы: проверка живучести

HTTP/2 использует PING для проверки соединения. Клиент отправляет PING, сервер отвечает таким же. Реализации различаются по таймингам.

Браузеры отправляют PING раз в 30 секунд. Прокси-серверы — раз в 5-10 секунд. Или не отправляют вообще. Антифрод замеряет интервалы и сверяет с профилем браузера.

Порядок фреймов: хронология выдачи

HTTP/2 соединение — это последовательность фреймов. SETTINGS, затем WINDOW_UPDATE, затем HEADERS, затем DATA. Порядок строгий.

Браузеры отправляют SETTINGS с ACK флагом сразу после получения SETTERS от сервера. Прокси-клиенты могут задержать ACK или отправить его не в том порядке.

```python

Неправильный порядок — сразу видно

import h2.config

config = h2.config.H2Configuration(client_side=True)

conn = h2.connection.H2Connection(config=config)

conn.initiate_connection()

Отправляем HEADERS до подтверждения SETTINGS — ошибка

conn.send_headers(1, [(':method', 'GET'), (':path', '/')])

```

Антифрод ловит такие аномалии. Если порядок фреймов не совпадает с эталонным для браузера — вы в бане.

Magic bytes: первые 24 байта

HTTP/2 соединение начинается с магической последовательности: `PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n`. Это 24 байта, которые отправляет клиент.

Браузеры отправляют их ровно один раз. Прокси-клиенты могут отправить их повторно при переподключении. Или не отправить вовсе, если используют upgrade с HTTP/1.1.

Антифрод проверяет наличие и количество этих байтов. Лишние магические последовательности — признак прокси.

Реальные кейсы из практики

Я видел, как один сервис блокировал все запросы, где `SETTINGS_MAX_CONCURRENT_STREAMS` был установлен в 256. Браузеры используют 100. Прокси-сервер использовал 256. Бан.

Другой случай — прокси на Node.js. Он отправлял WINDOW_UPDATE с размером 65535 байт. Chrome отправляет 6291456. Разница в 96 раз. Антифрод посчитал это аномалией.

Третий кейс — HPACK. Прокси не использовал динамическую таблицу вообще. Каждый заголовок передавался как литерал. Размер запроса вырос в 3 раза. Система увидела несоответствие размеров и заблокировала.

Как обходить

Обходить сложно. Нужно эмулировать поведение конкретного браузера. Не просто подменять User-Agent, а копировать всю последовательность фреймов, настройки SETTINGS, размеры окон.

Используйте библиотеки, которые поддерживают точную эмуляцию. Например, `aioquic` для Python или `nghttp2` для C. Они позволяют контролировать каждый фрейм.

```bash

Пример с nghttp2 — точная эмуляция Chrome

nghttp --no-dep --header-table-size=65536 --max-concurrent-streams=100 \

--initial-window-size=6291456 --max-frame-size=16384 \

https://example.com

```

Но даже это не панацея. Антифрод смотрит на тайминги. На порядок отправки фреймов. На то, как вы обрабатываете PING.

Выводы

HTTP/2 fingerprint — мощный инструмент. Он видит то, что скрыто от HTTP/1.1. HPACK, SETTINGS, WINDOW_UPDATE — каждый параметр может стать триггером.

Прокси-сервисы вроде lexic.ml пытаются эмулировать браузерное поведение. Но идеального решения нет. Антифрод постоянно совершенствуется.

Если вы используете прокси — проверяйте не только IP, но и HTTP/2 fingerprint. Иначе ваш трафик будет выглядеть как прокси-трафик. Даже если IP чистый.

✔️Купить прокси