HTTP/2 Fingerprint: как антифрод вычисляет прокси по циферкам в заголовках
Содержание
- Что за fingerprint и откуда он взялся
- Как антифрод собирает данные
- Почему обычный парсер палится
- Чем отличается браузер от прокси
- Как антифрод отличает человека от бота
- Реальный пример: Cloudflare и curl
- Что можно сделать: эмуляция браузерного fingerprint
- Пример с curl_cffi
- Прокси и fingerprint: как они связаны
- Кейс: почему парсер с прокси палится на Wildberries
- Кейс: Avito и HTTP/2 fingerprint
- Кейс: Ozon и поведенческий анализ
- Таблица сравнения fingerprint
- Что делать парсеру
- Как проверить свой fingerprint
- Итоги
Что за fingerprint и откуда он взялся
HTTP/2 — это не просто "вторая версия протокола". Это бинарный протокол с жёсткой структурой кадров. Каждый клиент — Chrome, Firefox, curl, Python requests — собирает эти кадры по-своему. Порядок настроек, размеры окон, приоритеты потоков — всё это оставляет след.
Антифрод-системы научились читать эти следы. Они сравнивают fingerprint входящего соединения с базой известных сигнатур. Совпадение с сигнатурой прокси-библиотеки — мгновенный бан.
Технически fingerprint — это хэш от последовательности SETTINGS-кадров, WINDOW_UPDATE, флагов PRIORITY, порядка HEADERS. Выглядит как строка типа `"3:0;4:4194304;5:16384;7:0"`. Разные библиотеки дают разные строки.
Как антифрод собирает данные
Антифрод не смотрит на один параметр. Он собирает мозаику:
- Порядок отправки SETTINGS-кадров
- Значения параметров (MAX_CONCURRENT_STREAMS, INITIAL_WINDOW_SIZE)
- Размеры HEADERS-кадров
- Использование HPACK-сжатия (какие заголовки сжаты, какие нет)
- Поведение при ошибках и таймаутах
- Поддержка push-запросов (или её отсутствие)
Каждый пункт — это отдельный признак. В совокупности они дают уникальный отпечаток.
Почему обычный парсер палится
Стандартный Python requests использует библиотеку h11 или httpx. Они отправляют SETTINGS в фиксированном порядке. Значения параметров — дефолтные. WINDOW_UPDATE — всегда одинаковый. Это как ходить в одной и той же одежде каждый день.
Пример: requests отправляет `SETTINGS_MAX_CONCURRENT_STREAMS=100`, `INITIAL_WINDOW_SIZE=65535`. Chrome отправляет `INITIAL_WINDOW_SIZE=6291456` (6 МБ) и `MAX_HEADER_LIST_SIZE=262144`. Разница в 100 раз. Антифрод это видит мгновенно.
Библиотеки прокси — те же. Squid, 3proxy, Dante — у каждой свой fingerprint. Если вы используете стандартный прокси-клиент, ваш трафик несёт его сигнатуру.
Чем отличается браузер от прокси
Браузеры эволюционировали десятилетиями. Их HTTP/2-стек оптимизирован под реальные сети. Прокси-библиотеки — это костыли, которые решают одну задачу: переслать пакет. Отсюда и разница.
Chrome 120 отправляет 15 SETTINGS-параметров, включая `ENABLE_CONNECT_PROTOCOL` и `ENABLE_PRIORITIZE_LOAD`. Python httpx — 4 параметра. Squid — 6. Разница в поведении при переполнении буфера, при ошибках декомпрессии — колоссальная.
Как антифрод отличает человека от бота
Человек не открывает 500 страниц за минуту. Он не запрашивает один и тот же ресурс с интервалом 0.7 секунды. Но это поведенческий анализ. Fingerprint — это более низкий уровень.
Антифрод строит модель: если fingerprint клиента совпадает с известным прокси-инструментом, а поведение — с паттерном парсера, то вероятность бота — 99%. Если fingerprint браузерный, но поведение ботоподобное — вероятность 70%. Если и то, и другое браузерное — 10%.
Реальный пример: Cloudflare и curl
Проверим, что видит Cloudflare при запросе с curl:
```bash
curl -v https://example.com 2>&1 | grep -E "HTTP/2|SETTINGS"
```
Вывод покажет `HTTP/2 200` и ничего про SETTINGS — curl их не логирует. Но на стороне сервера картина другая. Cloudflare видит:
```
SETTINGS_MAX_CONCURRENT_STREAMS: 100
SETTINGS_INITIAL_WINDOW_SIZE: 65535
SETTINGS_MAX_HEADER_LIST_SIZE: 65536
```
Это сигнатура curl 8.x. Она отличается от Chrome 120:
```
SETTINGS_HEADER_TABLE_SIZE: 65536
SETTINGS_ENABLE_PUSH: 0
SETTINGS_MAX_CONCURRENT_STREAMS: 1000
SETTINGS_INITIAL_WINDOW_SIZE: 6291456
SETTINGS_MAX_HEADER_LIST_SIZE: 262144
```
Разница видна невооружённым глазом. Cloudflare сверяет это с базой сигнатур и принимает решение.
Что можно сделать: эмуляция браузерного fingerprint
Полная эмуляция браузерного HTTP/2 — это сложно, но возможно. Нужно воспроизвести не только значения SETTINGS, но и порядок их отправки, размеры кадров, поведение при ошибках.
Библиотека `httpx` с HTTP/2 поддерживает настройку параметров:
```python
import httpx
client = httpx.Client(
http2=True,
headers={
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
)
response = client.get("https://example.com")
```
Но это не решает проблему. httpx использует h2-библиотеку, которая имеет свой fingerprint. Решение — использовать библиотеку, которая эмулирует браузерный стек. Например, `curl_cffi` — форк curl с поддержкой браузерных fingerprint.
Пример с curl_cffi
```python
from curl_cffi import requests
session = requests.Session(impersonate="chrome120")
response = session.get("https://example.com")
print(response.status_code)
```
`curl_cffi` эмулирует fingerprint Chrome 120. Он отправляет те же SETTINGS, те же WINDOW_UPDATE, тот же порядок кадров. Это уже не палится по HTTP/2.
Но есть нюанс. Эмуляция не идеальна. Chrome 120 отправляет `SETTINGS_ENABLE_PUSH: 0`, но curl_cffi может отправить это в другом порядке. Антифрод сравнивает не только значения, но и последовательность.
Прокси и fingerprint: как они связаны
Прокси-сервер — это посредник. Он принимает соединение от клиента и устанавливает своё соединение с целевым сервером. Fingerprint зависит от клиента, который установил соединение с прокси.
Если вы используете прокси с клиентом curl_cffi, то fingerprint будет браузерным. Если с обычным requests — fingerprint будет Python-библиотеки. Прокси не влияет на fingerprint, он только передаёт данные.
Но есть исключение. Некоторые прокси модифицируют заголовки. Например, Squid добавляет заголовок `Via`. Это меняет fingerprint. Антифрод это видит.
Кейс: почему парсер с прокси палится на Wildberries
Пример: парсер на Python requests с прокси SOCKS5 от lexic.ml. Запросы идут через прокси, но fingerprint остаётся Python-библиотеки. Wildberries использует антифрод, который сверяет HTTP/2 сигнатуры.
Первые 50 запросов проходят. Потом антифрод замечает: все запросы имеют одинаковый fingerprint, интервалы между запросами — 1.2 секунды, user-agent — Python-requests. Решение: блокировка по IP прокси. Парсер останавливается.
Решение: перейти на curl_cffi с эмуляцией Chrome, добавить случайные задержки, менять user-agent. После этого парсер работает стабильно.
Кейс: Avito и HTTP/2 fingerprint
Avito использует свою антифрод-систему. Она анализирует не только HTTP/2, но и TLS fingerprint. Прокси-серверы с TLS-терминацией имеют свои сигнатуры.
Пример: парсер через HTTPS-прокси. Прокси устанавливает TLS-соединение с Avito. TLS fingerprint прокси (OpenSSL 3.0) отличается от браузерного (BoringSSL). Антифрод это видит.
Решение: использовать прокси с поддержкой TLS-эмуляции. Или использовать SOCKS5, где TLS-соединение устанавливает клиент, а не прокси.
Кейс: Ozon и поведенческий анализ
Ozon использует комбинацию HTTP/2 fingerprint и поведенческого анализа. Парсер с браузерным fingerprint работает, но если он делает 100 запросов в минуту — это подозрительно.
Решение: добавить случайные задержки между запросами (2-5 секунд), использовать несколько прокси, распределять нагрузку. Fingerprint важен, но поведение — тоже.
Таблица сравнения fingerprint
| Клиент | SETTINGS_MAX_CONCURRENT_STREAMS | INITIAL_WINDOW_SIZE | MAX_HEADER_LIST_SIZE | Порядок SETTINGS |
|--------|--------------------------------|---------------------|----------------------|------------------|
| Chrome 120 | 1000 | 6291456 | 262144 | 0,1,2,3,4,5,6,7 |
| Firefox 120 | 100 | 131072 | 65536 | 0,2,3,4,5,6 |
| curl 8.x | 100 | 65535 | 65536 | 0,2,3,4,5 |
| Python httpx | 100 | 65535 | 65536 | 0,2,3,4,5 |
| Squid 6 | 100 | 65535 | 65536 | 0,2,3,4,5,6 |
Видно, что curl и httpx почти идентичны. Это проблема — антифрод легко их распознаёт.
Что делать парсеру
Полностью скрыть fingerprint невозможно. Всегда есть отличия. Но можно минимизировать риски.
Первое: используйте curl_cffi с эмуляцией браузера. Это решает 80% проблем.
Второе: используйте SOCKS5-прокси вместо HTTP-прокси. TLS-соединение устанавливает клиент, а не прокси. Fingerprint TLS будет браузерным.
Третье: распределяйте нагрузку. Один прокси — один парсер. Не делайте 1000 запросов через один IP.
Четвёртое: анализируйте свои запросы. Смотрите, какие заголовки отправляете. Убирайте лишние. Добавляйте браузерные.
Как проверить свой fingerprint
Есть сервисы, которые показывают ваш HTTP/2 fingerprint. Например, `tls.peet.ws` или `browserleaks.com/http2`. Зайдите через браузер и через свой парсер. Сравните.
```bash
curl -s https://tls.peet.ws/api/all | jq '.http2'
```
Вывод покажет ваши SETTINGS и fingerprint. Сравните с браузерным.
Итоги
HTTP/2 fingerprint — это серьёзный инструмент антифрода. Он работает на уровне протокола и не зависит от IP-адреса. Прокси не спасают от fingerprint, если клиент использует стандартные библиотеки.
Решение — эмуляция браузерного стека. Библиотеки типа curl_cffi это умеют. Но даже они не идеальны. Антифрод постоянно обновляет базы сигнатур.
Парсер должен быть гибким. Используйте несколько подходов, комбинируйте прокси, эмулируйте браузеры, анализируйте свой трафик. Тогда шансы на долгую жизнь парсера вырастут.
Помните: антифрод — это тоже код. Он имеет баги, ограничения, слабые места. Изучайте его, тестируйте свои решения, адаптируйтесь. Это бесконечная гонка.