Объяснение HTTP/2 фингерпринтинга: что обнаруживают антибот-системы
Когда ваш скрапер подключается к серверу по HTTP/2, сервер видит больше, чем просто URL и заголовки. Он видит точную последовательность кадров SETTINGS, значения WINDOW_UPDATE, приоритеты потоков и порядок pseudo-заголовков — всё это формирует уникальный отпечаток, который отличает Chrome от httpx, а Firefox от aiohttp. Это и есть HTTP/2 фингерпринтинг, и в 2026 году он стал одним из основных методов обнаружения автоматизации. В этой статье — подробное объяснение HTTP/2 фингерпринтинга: от кадра SETTINGS до JA4H, от Akamai h2 fingerprint до практической реализации с residential прокси ProxyHat.
Проблема, с которой сталкиваются инженеры: большинство Python-библиотек для HTTP-запросов отправляют кадры SETTINGS со значениями по умолчанию, которые кардинально отличаются от того, что отправляет реальный браузер. Антибот-системы вроде Akamai Bot Manager, Cloudflare Bot Management и DataDome сравнивают ваш h2 fingerprint с базой известных браузеров — и если значения не совпадают, вам присваивается максимальный bot-score ещё до того, как сервер вернёт HTML.
Что именно фингерпринтится: разбивка по кадрам
HTTP/2 — бинарный протокол, и каждый кадр в нём имеет чёткую структуру. Когда клиент устанавливает соединение, он отправляет RFC 9113 connection preface, за которым следует кадр SETTINGS. Этот кадр — первый и самый важный сигнал для фингерпринтинга, потому что каждое приложение выбирает свои значения параметров.
Кадр SETTINGS и h2 settings frame
Кадр SETTINGS содержит набор параметров, которые клиент сообщает серверу. Вот ключевые параметры, которые фингерпринтятся:
- HEADER_TABLE_SIZE (0x1) — размер таблицы сжатия заголовков HPACK. Chrome использует 65536 байт, httpx/h2 — 4096 байт. Разница в 16 раз.
- ENABLE_PUSH (0x2) — включает server push. Chrome отправляет 0 (отключено), некоторые библиотеки не отправляют этот параметр вообще.
- MAX_CONCURRENT_STREAMS (0x3) — максимальное число параллельных потоков. Chrome: 1000, httpx: 100 или не установлено.
- INITIAL_WINDOW_SIZE (0x4) — начальный размер окна потока. Chrome: 6291456 байт (6 МБ), httpx/h2: 65535 байт (значение по умолчанию из спецификации).
- MAX_FRAME_SIZE (0x5) — максимальный размер кадра. Chrome: 16384 байт, httpx: 16384 (совпадает).
- MAX_HEADER_LIST_SIZE (0x6) — максимальный размер списка заголовков. Chrome: 262144 байта, httpx: не отправляет.
Порядок, в котором эти параметры перечислены в кадре SETTINGS, также важен. Chrome отправляет их в определённой последовательности, и нарушение этого порядка — дополнительный сигнал для антибот-систем.
Кадр WINDOW_UPDATE
Сразу после SETTINGS клиент отправляет кадр WINDOW_UPDATE на уровне соединения. Chrome увеличивает окно управления потоком соединения на 15663105 байт, что в сумме с начальным значением 65535 даёт 15728640 байт (15 МБ). httpx и h2-библиотеки обычно не отправляют этот кадр или отправляют с другим значением.
Это значение — один из самых надёжных сигналов для Akamai h2 fingerprint, потому что оно специфично для каждого браузера и редко совпадает между библиотеками.
Приоритеты потоков (Stream Priority)
HTTP/2 позволяет клиенту указывать приоритеты потоков через кадры PRIORITY (в HTTP/2, устаревший в RFC 9113) или через заголовок Priority (в HTTP/3). Chrome отправляет специфические шаблоны приоритетов, которые зависят от типа ресурса (HTML, CSS, JS, изображения). Эти шаблоны формируют дополнительный отпечаток.
В 2026 году большинство браузеров перешли на RFC 9218 (Extensible Prioritization Scheme), но legacy-кадры PRIORITY всё ещё используются для фингерпринтинга, потому что их наличие или отсутствие — это сигнал.
Порядок pseudo-заголовков
HTTP/2 использует pseudo-заголовки (:method, :authority, :scheme, :path) вместо строк запроса HTTP/1.1. Порядок этих заголовков — мощный сигнал:
- Chrome: :method, :authority, :scheme, :path (сокращённо
m,a,s,p) - Firefox: :method, :path, :scheme, :authority (сокращённо
m,p,s,a) - httpx/h2: :method, :authority, :scheme, :path (
m,a,s,p) — совпадает с Chrome, но другие параметры не совпадают
Порядок m,a,s,p сам по себе не спасает — антибот-системы смотрят на всю совокупность сигналов.
Akamai h2 fingerprint string
Akamai был одним из первых CDN, который начал использовать HTTP/2 фингерпринтинг. Их формат объединяет кадры SETTINGS, WINDOW_UPDATE, приоритеты и порядок pseudo-заголовков в компактную строку. Формат примерно такой:
SETTINGS|WINDOW_UPDATE|PRIORITY|PSEUDO_HEADERS
Например, отпечаток Chrome может выглядеть как:
1:65536;2:0;3:1000;4:6291456;5:16384;6:262144|15663105|0|m,a,s,p
Где 1:65536 означает HEADER_TABLE_SIZE=65536, 2:0 — ENABLE_PUSH=0, и так далее. Антибот-система сравнивает эту строку с базой известных браузеров. Если строка не совпадает ни с одним известным браузером — бот-score повышается.
JA4H fingerprint
JA4H — это HTTP-фингерпринт из семейства JA4 от FoxIO. В отличие от Akamai h2 fingerprint, JA4H фокусируется на HTTP-запросе в целом: метод, версия протокола, количество заголовков, имена заголовков (отсортированные), наличие cookie и referer. Формат создаёт компактную строку, которая однозначно идентифицирует поведение клиента.
JA4H дополняет HTTP/2 fingerprint: если h2 fingerprint говорит «это Chrome на уровне протокола», JA4H проверяет «это Chrome на уровне HTTP-заголовков». Несоответствие между ними — красный флаг для антибот-систем.
Почему httpx с HEADER_TABLE_SIZE 4096 получает максимальный bot-score
Рассмотрим конкретный сценарий. Вы используете httpx с TLS-имперсонизацией через curl_cffi или custom TLS-библиотеку. Ваш JA4 говорит «Chrome 148». Но ваш HTTP/2 кадр SETTINGS говорит:
HEADER_TABLE_SIZE: 4096
INITIAL_WINDOW_SIZE: 65535
MAX_CONCURRENT_STREAMS: 100
Chrome 148 отправляет:
HEADER_TABLE_SIZE: 65536
INITIAL_WINDOW_SIZE: 6291456
MAX_CONCURRENT_STREAMS: 1000
Антибот-система видит: TLS-отпечаток = Chrome, HTTP/2-отпечаток = неизвестный клиент. Это несоответствие — автоматический максимальный bot-score. Серверу не нужно анализировать HTML, JavaScript или поведение — достаточно одного кадра SETTINGS.
Вот почему простая замена TLS-библиотеки (например, использование curl_cffi для JA3/JA4) без изменения HTTP/2 параметров не работает. Антибот-системы проверяют согласованность на всех уровнях.
Ключевой вывод: TLS-фингерпринт и HTTP/2 fingerprint должны согласовываться. Если ваш JA4 говорит Chrome, ваш h2 fingerprint тоже должен быть Chrome. Несоответствие на любом уровне — мгновенная блокировка.
Согласованность TLS (JA3/JA4) и HTTP/2
TLS-фингерпринтинг (JA3/JA4) анализирует ClientHello — пакет, который клиент отправляет в начале TLS-рукопожатия. JA3 создаёт хеш из версии TLS, списка шифров, расширений и эллиптических кривых. JA4 — улучшенная версия с более структурированным форматом, который разделяет компоненты для более гибкого сравнения.
Проблема согласованности: если вы используете библиотеку, которая подделывает JA3/JA4, но не подделывает HTTP/2 SETTINGS, вы создаёте гибрид, которого не существует в природе. Антибот-системы имеют базы реальных комбинаций «TLS + HTTP/2» для каждого браузера:
| Клиент | JA4 (TLS) | h2 HEADER_TABLE_SIZE | h2 INITIAL_WINDOW_SIZE | h2 MAX_CONCURRENT_STREAMS | WINDOW_UPDATE | Соответствие |
|---|---|---|---|---|---|---|
| Chrome 131+ | Chrome | 65536 | 6291456 | 1000 | 15663105 | Полное |
| Firefox 134+ | Firefox | 65536 | 131072 | 1000 | 12517377 | Полное |
| httpx (Python) | OpenSSL | 4096 | 65535 | 100 | 0 | Несоответствие |
| aiohttp (Python) | OpenSSL | 4096 | 65535 | 100 | 0 | Несоответствие |
| curl_cffi (chrome131) | Chrome | 65536 | 6291456 | 1000 | 15663105 | Полное |
| Node.js http2 | OpenSSL/Node | 4096 | 65535 | 100 | 0 | Несоответствие |
Какие Python/Node клиенты утечкают несогласованные кадры:
- httpx — использует h2-библиотеку с значениями по умолчанию. TLS через OpenSSL, который не совпадает ни с одним браузером.
- aiohttp — аналогично httpx, использует h2 с значениями по умолчанию.
- requests — вообще не поддерживает HTTP/2, что само по себе подозрительно в 2026 году.
- Node.js http2 — встроенный модуль http2 использует значения по умолчанию, отличные от Chrome.
- got (Node.js) — использует http2-wrapper с теми же значениями по умолчанию.
Единственные библиотеки, которые корректно подделывают HTTP/2 fingerprint вместе с TLS:
- curl_cffi (Python) — обёртка вокруг curl-impersonate, подделывает и TLS, и HTTP/2.
- Playwright/Puppeteer — используют реальный браузер, отпечаток нативный.
- undetected-chromedriver — реальный Chrome, отпечаток нативный.
Почему residential прокси всё ещё необходимы
Даже если вы идеально подделали TLS и HTTP/2 fingerprint, у вас остаётся одна проблема: IP-адрес. Антибот-системы проверяют IP-репутацию параллельно с протокольным фингерпринтингом. Вот почему protocol spoofing alone не работает:
Если ваш отпечаток говорит «Chrome 148 на residential IP в Берлине», но ваш IP — это datacenter IP из AWS us-east-1, антибот-система видит несоответствие. Chrome на datacenter IP — это подозрительно. Datacenter IP с идеальным отпечатком = ещё более подозрительно, потому что реальные пользователи не сидят на datacenter IP.
Residential прокти решают эту проблему, предоставляя IP-адреса, которые принадлежат реальным ISP. Когда вы комбинируете:
- Когерентный TLS + HTTP/2 fingerprint (через curl_cffi или реальный браузер)
- Residential IP-адрес (через ProxyHat)
- Правильное гео-таргетирование (страна/город)
— вы получаете отпечаток, который неотличим от реального пользователя. ProxyHat предоставляет residential, mobile и datacenter прокси. Для задач, где критична IP-репутация, residential прокси — единственный правильный выбор. См. тарифы ProxyHat и доступные локации.
Практическая реализация: curl_cffi + ProxyHat
Рассмотрим рабочий пример: скрапинг с когерентным Chrome h2 fingerprint через residential прокси ProxyHat. Этот подход подходит для авторизованного мониторинга и исследований.
Вариант 1: curl_cffi с impersonate
from curl_cffi import requests
# ProxyHat residential proxy с гео-таргетированием на США
proxy_url = "http://user-country-US:YOUR_PASSWORD@gate.proxyhat.com:8080"
response = requests.get(
"https://example.com",
proxies={"https": proxy_url, "http": proxy_url},
impersonate="chrome131", # согласованный TLS + h2 fingerprint
timeout=30
)
print(f"Status: {response.status_code}")
print(f"Body length: {len(response.text)}")
Ключевой параметр — impersonate="chrome131". curl_cffi использует curl-impersonate под капотом, который подделывает и TLS ClientHello (JA3/JA4), и HTTP/2 кадры SETTINGS, WINDOW_UPDATE и порядок pseudo-заголовков. Версия impersonate должна соответствовать версии браузера, которую вы имитируете.
Вариант 2: Sticky session для серии запросов
from curl_cffi import requests
# Sticky session — один IP для серии запросов
session_id = "serp-scrape-20260115"
proxy_url = f"http://user-session-{session_id}-country-US:YOUR_PASSWORD@gate.proxyhat.com:8080"
urls = [
"https://example.com/page1",
"https://example.com/page2",
"https://example.com/page3",
]
for url in urls:
response = requests.get(
url,
proxies={"https": proxy_url, "http": proxy_url},
impersonate="chrome131",
timeout=30
)
print(f"{url} -> {response.status_code}")
Sticky session гарантирует, что все запросы в серии идут с одного IP-адреса. Это важно для скрапинга, где сервер ожидает, что пользователь сохраняет один IP в течение сессии.
Вариант 3: Гео-таргетирование на город
from curl_cffi import requests
# Гео-таргетирование на Берлин, Германия
proxy_url = "http://user-country-DE-city-berlin:YOUR_PASSWORD@gate.proxyhat.com:8080"
response = requests.get(
"https://example.com",
proxies={"https": proxy_url, "http": proxy_url},
impersonate="chrome131",
timeout=30
)
Гео-таргетирование на город важно для задач, где контент зависит от местоположения — например, SERP-трекинг или ценовой мониторинг.
Вариант 4: SOCKS5 для сценариев с повышенными требованиями
from curl_cffi import requests
# SOCKS5 прокси через ProxyHat
proxy_url = "socks5://user-country-US:YOUR_PASSWORD@gate.proxyhat.com:1080"
response = requests.get(
"https://example.com",
proxies={"https": proxy_url, "http": proxy_url},
impersonate="chrome131",
timeout=30
)
Вариант 5: Реальный браузер через Playwright + ProxyHat
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(
headless=True,
proxy={
"server": "http://gate.proxyhat.com:8080",
"username": "user-country-US",
"password": "YOUR_PASSWORD"
}
)
page = browser.new_page()
page.goto("https://example.com")
content = page.content()
print(f"Page length: {len(content)}")
browser.close()
Playwright использует реальный Chromium, поэтому TLS и HTTP/2 fingerprint нативные. Это самый надёжный, но и самый ресурсоёмкий подход. Подробнее о использовании прокси для веб-скрапинга.
HTTP/3 и QUIC fingerprinting
HTTP/3 работает поверх QUIC, и у него свои сигналы для фингерпринтинга. QUIC transport parameters отправляются в TLS-рукопожатии внутри CRYPTO-кадров. Ключевые параметры:
- initial_max_data — максимальный объём данных на уровне соединения.
- initial_max_stream_data_bidi_local — максимальный объём данных на двунаправленном потоке.
- initial_max_streams_bidi — максимальное число параллельных потоков.
- max_idle_timeout — тайм-аут неактивности.
- active_connection_id_limit — лимит идентификаторов соединений.
Значения и порядок этих параметров формируют QUIC fingerprint. Chrome, Firefox и Safari отправляют разные наборы параметров. В 2026 году HTTP/3 fingerprinting менее распространён, чем HTTP/2, потому что не все сайты поддерживают HTTP/3, и не все антибот-системы его анализируют. Но тренд указывает на то, что QUIC fingerprinting станет стандартом в ближайшие годы.
curl_cffi поддерживает HTTP/3 при использовании соответствующих сборок curl-impersonate, но не все версии имперсонации корректно подделывают QUIC transport parameters. Для критичных задач рекомендуется использовать реальный браузер через Playwright.
Распространённые ошибки и edge cases
Ошибка 1: Только TLS-имперсонизация
Многие инженеры используют curl_cffi или tls-client для подделки JA3/JA4, но забывают проверить HTTP/2 fingerprint. Если библиотека подделывает TLS, но не HTTP/2, вы получаете несогласованный отпечаток. curl_cffi — одно из немногих исключений, которое подделывает оба уровня.
Ошибка 2: Несоответствие версии браузера
Если ваш JA4 говорит «Chrome 131», но вы отправляете заголовок User-Agent с Chrome 148, антибот-система видит несоответствие. Версия в impersonate должна совпадать с User-Agent.
Ошибка 3: Игнорирование порядка заголовков
JA4H включает порядок заголовков. Если вы добавляете заголовки в случайном порядке, JA4H не совпадёт с браузером. curl_cffi сохраняет порядок заголовков, но если вы добавляете свои заголовки поверх, порядок может нарушиться.
Ошибка 4: Слишком много параллельных запросов с одного IP
Даже с идеальным fingerprint и residential IP, 100 параллельных запросов с одного IP — подозрительно. Используйте ротацию IP или ограничьте параллельность до 5–10 запросов на IP.
Ошибка 5: Игнорирование HTTP/3 fallback
Некоторые сайты поддерживают HTTP/3 через Alt-Svc. Если ваш клиент не поддерживает HTTP/3, он может быть помечен как не-браузер. Chrome автоматически использует HTTP/3, когда доступно.
Надлежащее использование и правовые оговорки
HTTP/2 фингерпринтинг и его обход — инструменты с двойным применением. Легитимные сценарии включают:
- Авторизованный мониторинг — когда вы скрапите сайты с разрешения владельца или в рамках публично доступных данных.
- Security research — анализ антибот-систем для оценки их эффективности в рамках authorized pentesting.
- QA-тестирование — проверка ваших собственных систем защиты.
- Конкурентный анализ — ценовой мониторинг в рамках fair use и соблюдения ToS.
Нелегитимные сценарии, которые мы не поддерживаем:
- Обход защиты для мошенничества (ticketing, sneaker bots).
- Скрапинг персональных данных без согласия (нарушение GDPR).
- DDoS или атака на инфраструктуру.
- Нарушение Computer Fraud and Abuse Act (CFAA) в США или аналогичных законов в других юрисдикциях.
Всегда проверяйте robots.txt, условия использования сайта и применимое законодательство. Документация ProxyHat доступна на docs.proxyhat.com.
Key Takeaways
- HTTP/2 фингерпринтинг анализирует кадры SETTINGS, WINDOW_UPDATE, приоритеты потоков и порядок pseudo-заголовков для идентификации клиента.
- Akamai h2 fingerprint объединяет эти сигналы в компактную строку, которую антибот-системы сравнивают с базой известных браузеров.
- HEADER_TABLE_SIZE 4096 (httpx/h2 по умолчанию) мгновенно демаскирует ваш скрапер, потому что Chrome использует 65536.
- JA4H fingerprint дополняет h2 fingerprint, анализируя HTTP-заголовки. Несоответствие между JA4 (TLS), h2 fingerprint и JA4H — красный флаг.
- curl_cffi — единственная Python-библиотека, которая подделывает и TLS, и HTTP/2 fingerprint согласованно.
- Residential прокси необходимы, потому что protocol spoofing alone не проходит IP-reputation проверку.
- HTTP/3/QUIC fingerprinting — развивающаяся область, которая станет стандартом в ближайшие годы.
- Используйте эти техники только для легитимных задач: авторизованный мониторинг, security research, QA.






