Серверный фингерпринтинг: четыре слоя до JavaScript

Давайте начистоту. Когда люди говорят про фингерпринтинг, они думают про JavaScript. Canvas, WebGL, AudioContext, перебор шрифтов. Расширения, которые всё это глушат. Антидетект-браузеры, которые всё это подменяют. Зелёные галочки в интерфейсе, от которых на душе спокойно.
Спокойствие ложное. Контроль есть, но не ваш.
Между нажатием Enter и моментом, когда JavaScript получит голос, проходят четыре рукопожатия. TCP SYN-пакет выдаёт серверу операционную систему. TLS Client Hello сдаёт браузер и версию. HTTP/2 SETTINGS-фрейм транслирует диалект. HTTP-заголовки раскрывают порядок мыслей. Сто миллисекунд. Сервер уже собрал досье.
Расширение браузера не умеет подделывать TCP-пакеты: их собирает ядро ОС. Не может перехватить TLS Client Hello: тот уходит из скомпилированного сетевого стека. Не контролирует HTTP/2 SETTINGS: они вбиты в исходники Chromium. Зона, куда Manifest V3 не дотягивается. Ничего из мира установить расширение за два клика сюда не дотягивается.
Коротко: Сервер определяет ОС, браузер, VPN и маршрут за 100 мс. Без JavaScript. Через четыре рукопожатия, о которых ваш браузер вас не предупреждает. Расширения этого не видят, потому что всё идёт уровнем ниже, там, где расширений попросту нет.
Слой 0: TCP/IP. Нулевая миллисекунда
Браузер отправляет SYN-пакет. Первый пакет TCP-соединения. Один-единственный. Ноль полезной нагрузки.
Этот пакет уже всё рассказал.
Каждая ОС строит TCP по-своему. Не в том, что она делает, а в том, как именно. Инженеры Windows когда-то выбрали одни параметры сетевого стека. Инженеры Linux выбрали другие. Решения приняты десятилетия назад и с тех пор намертво впаяны в ядро миллиардов устройств. Изменить нельзя. Отключить нельзя. Они уходят в сеть с каждым первым пакетом каждого соединения.
| ОС | Window Size | TCP Options | MSS | Window Scale |
|---|---|---|---|---|
| Windows 10/11 | 65535 | 2-4-8-1-3 | 1460 | 8 |
| Linux 5.x+ | 29200 | 2-4-8-1-3 | 1460 | 7 |
| macOS | 65535 | 2-4-8-1-3 | 1460 | 6 |
| iOS | 65535 | 2-4-8-1-3-0 | 1460 | 6 |
| Android 13 | 65535 | 2-4-8-1-3 | 1460 | 9 |
iOS дописывает TCP Option 0, End of List, в конец. Больше так не делает никто. Зачем Apple так решила, загадка. Для наблюдателя смысл очевиден: привет, я iPhone. Android задирает window scale до 9, выше всех десктопов. Windows принципиально не отсылает TCP Timestamps. У каждой ОС свой росчерк в первом пакете. Росчерк, о котором вас не спрашивали.
John Althouse из FoxIO задокументировал это в 2024 году, выпустив JA4T. Формат: window_size_options_mss_windowscale. Отпечаток 29200_2-4-8-1-3_1424_7 читается так: Linux, но MSS 1424 вместо стандартных 1460. Разница 36 байт, накладные расходы туннеля. Вместе с GreyNoise они прогнали JA4T по глобальному трафику и нашли сотни IP с одинаковым отпечатком. Все принадлежали Tencent. Сотни сканирующих машин опознаны по одному полю одного пакета.
MSS это рентген маршрута. 1460 значит прямой Ethernet, ничего между вами и сервером. 1380 значит VPN или туннель: шифрование съело 80 байт. WireGuard, OpenVPN, IPsec: у каждого свой overhead, по которому видно протокол. Мобильные операторы задают собственные MSS. Althouse показал, что JA4T порой различает T-Mobile и Verizon по одному SYN-пакету. Оператор связи из одного пакета.
WHOX проверяет это в сигналах A06 и C09. Анализ завершается до того, как браузер отправит первый байт контента. Вы не постучали. Вас уже обыскали.
p0f и четверть века подслушивания
Ничего из этого не началось в 2024-м. 10 июня 2000 года Michal Zalewski выложил p0f на Bugtraq. Пассивное определение ОС. Без отправки единого пакета. Просто слушаешь, как чужие машины здороваются, и читаешь, кто перед тобой. TTL, размер окна, MSS, бит Don't Fragment, порядок TCP-опций. Каждая ОС делала чуть иначе.
В отличие от nmap, который ломится как слон в посудную лавку и палится на каждом файрволе, p0f молчал. Призрак. Невозможно засечь наблюдателя, который ничего не отправляет. Камера без красного огонька.
OpenBSD встроил логику p0f в файрвол PF в 2003 году. Администраторы писали правила фильтрации по ОС подключающейся машины. Идея не поменялась за два десятилетия. Инструменты стали на порядки острее.
eBPF: фингерпринтинг на скорости ядра
В 2025-м Alberto Ventafridda опубликовал Go-вебсервер, использующий eBPF для перехвата TCP SYN на сетевом интерфейсе, до того, как пакет доберётся до TCP-стека ядра. Отпечаток сохраняется в eBPF hashmap в kernel-space. Ноль копирования. Ноль потоков. Ноль добавленной задержки.
Мотивация: гонка вооружений LLM-скрейперов. Генеративный ИИ нуждается в данных. Мир данных нуждается в защите от тех, кто данные крадёт. Побочный продукт этой войны: инструмент, который определяет вас по первому пакету. Ещё до того, как вы постучали.
Модели, которые не переезжают
Ifip Networking 2025 показал: Random Forest на TCP/IP-заголовках даёт отличный F1-score, но модель, обученная на трафике одного провайдера, проседает на трафике другого. Каждый наблюдатель видит свою версию одного и того же устройства. Слабое утешение: не единая система слежки, а куча несовместимых. Лоскутная слежка всё равно остаётся слежкой.
Пульс вместо подписи
TCP congestion control поддаётся пассивной идентификации. TU Munich, 2022. Linux использует Cubic. Google серверы крутят BBR. Windows 11 24H2 добавил BBRv2. Отличить их можно, наблюдая за паттернами окна перегрузки. Это не подпись. Это пульс. У каждой ОС свой сердечный ритм. На том конце провода стоит стетоскоп. Ни одно расширение не контролирует, как ядро управляет перегрузкой. Ещё один вектор, о котором никто пока не думает.
Слой 1: TLS Client Hello. 20-50 мс
TCP-соединение установлено. Браузер настраивает шифрование. Для этого отправляет TLS Client Hello. Открытым текстом. Потому что шифрование надо согласовать до того, как можно шифровать. Звучит как архитектурная проблема, потому что это и есть архитектурная проблема.
Client Hello содержит поддерживаемые версии TLS, наборы шифров, расширения, эллиптические кривые, предпочтения Alpn. Chrome не похож на Firefox. Python requests не похож ни на один из них. Разные версии одного браузера дают различающиеся отпечатки. Это развёрнутая характеристика вашего софтового стека, отправленная открытым текстом каждому устройству на пути.
JA3 и JA4
В 2017-м Salesforce выпустил JA3: хеш Client Hello на основе порядка cipher suites и расширений. Работал отменно, пока Chrome 108 в конце 2022 не начал тасовать порядок TLS-расширений. Один браузер стал давать разные JA3 при каждом подключении. Занавес.
JA4 нашёл выход: сортировка расширений перед хешированием. Тасуй как хочешь, после сортировки порядок всегда один. По данным Peakhour, точность 99%.
Анатомия JA4: t13d1516h2_8daaf6152771_02713d6af862. Первая часть: протокол, версия TLS, наличие SNI, количество шифров, количество расширений, Alpn. Вторая: хеш отсортированных шифров. Третья: хеш отсортированных расширений. Одна строка, три уровня идентификации.
Масштаб Cloudflare
Cloudflare обрабатывает 15 миллионов уникальных JA4-отпечатков в день. Видит 500 миллионов user agents. В октябре 2025-го запустили JA4 Signals: метрики, вычисленные по всему глобальному трафику за последний час. Для каждого отпечатка показывают, какие user agents с ним обычно ходят, из каких стран, в какие часы. Не ваш трафик. Трафик всей планеты, проиндексированный по JA4.
Кто внедрил JA4: Cloudflare, AWS WAF, AWS CloudFront, Google Cloud Armor, Azure, Akamai, Fastly, Vercel, Palo Alto, CrowdStrike, Wireshark, Zeek, Suricata, HAProxy, Nginx, F5. Перечитайте список. Это не экзотика. Это водопроводные трубы интернета.
Cloudflare переписал свой парсер Client Hello на Rust. Один крейт. Ноль аллокаций в куче. Simd-кодирование hex. Два миллиона элементов в секунду. Продакшн на масштабе 20% мирового веб-трафика.
Когда говорят, что никто не следит, вот этот список следит. Круглосуточно. На каждом рукопожатии.
Парадокс ECH
Encrypted Client Hello, RFC одобрен в октябре 2025, шифрует SNI: прячет, какой сайт вы посещаете. Вроде бы победа. На деле Cisco EVE в декабре 2025-го показал идентификацию сессии со 100% уверенностью по Outer Client Hello и TLS-отпечатку даже при включённом ECH.
ECH зашифровал адрес получателя на конверте. Почерк, бумага, марка и обратный адрес по-прежнему видны. Зашифровали куда. Не зашифровали кто.
И хуже того. ECH раздувает поверхность фингерпринтинга. Outer Client Hello с паттерном Grease ECH extension сам становится новым вектором идентификации. Браузеры с ECH выглядят иначе, чем без ECH. По данным Mdpi 2025, из 106 миллионов QUIC-соединений ECH используют около 2%. Включив ECH ради приватности, вы вступили в группу из двух процентов, которую отследить проще, чем остальные девяносто восемь. Хотели спрятаться, а натянули жёлтый жилет. Не баг. Статистика.
Слой 2: HTTP/2 SETTINGS. 50-80 мс
TLS-рукопожатие завершено. Канал зашифрован. Казалось бы, теперь-то всё закрыто? Рано радоваться.
Браузер отправляет HTTP/2 SETTINGS-фрейм, первый фрейм HTTP/2-соединения. В нём параметры, которые браузер считает оптимальными. Ory Segal из Akamai описал это в whitepaper на Black Hat EU 2017: SETTINGS-фрейм работает как диалект. Все говорят на HTTP/2, но у каждого свой акцент.
| Параметр | Chrome | Firefox | Safari | curl |
|---|---|---|---|---|
| HEADER_TABLE_SIZE | 65536 | 65536 | 4096 | 4096 |
| ENABLE_PUSH | 0 | 0 | 1 | 0 |
| MAX_CONCURRENT_STREAMS | 1000 | 100 | 100 | 100 |
| INITIAL_WINDOW_SIZE | 6291456 | 131072 | 2097152 | 1073741824 |
| MAX_HEADER_LIST_SIZE | 262144 | 65536 | > | > |
curl выставляет INITIAL_WINDOW_SIZE в 1 073 741 824 байт. Гигабайт. Ни один браузер на планете так не делает. Если сервер видит это число, разговор окончен: по ту сторону скрипт. Можно поменять User-Agent, подкрутить заголовки, врубить headless. INITIAL_WINDOW_SIZE в гигабайт палит мгновенно.
Помимо SETTINGS, отличается порядок псевдозаголовков. Chrome отправляет :method, :authority, :scheme, :path. Firefox по-другому. Safari по-третьему. Порядок не настраивается. Он задаётся при компиляции и не меняется до следующей сборки.
Подделать сложнее, чем TLS
TLS-отпечаток можно сменить, перекомпилировав OpenSSL или подставив другую библиотеку. HTTP/2-параметры вшиты в сетевой стек, в скомпилированный код, который пользователь и в глаза не видит. Чтобы их подменить, нужен форк браузера. Не расширение. Не настройка. Форк.
Именно так появился curl-impersonate. Полный форк curl с пропатченным BoringSSL и вручную воспроизведёнными HTTP/2-параметрами Chrome, Firefox и Safari. Авторы перелопатили исходники каждого целевого браузера, вытащили параметры и перенесли к себе. Чтобы подделать один сетевой отпечаток, пришлось форкнуть один из фундаментальных инструментов интернета. Как если бы ради подделки чужого почерка пришлось заново учиться каллиграфии. Возможно, но охотников мало.
WHOX ловит несоответствие в сигнале A18. Браузер представляется Chrome, а SETTINGS-фрейм показывает curl. Как человек, который называет себя лондонцем, но говорит с акцентом из Манчестера.
Priority как временной отпечаток
HTTP/2 Priority-фреймы показывают, какие ресурсы браузер запрашивает первыми и какие зависимости ставит между потоками. Модель приоритетов Chrome кардинально изменилась при переходе с HTTP/2 на HTTP/3. Это создаёт темпоральный отпечаток: Priority указывает не просто на браузер, а на конкретный диапазон версий. Хронология обновлений, вплетённая в сетевое поведение.
Слой 3: HTTP-заголовки. 80-100 мс
Наконец браузер отправляет GET-запрос с заголовками. После трёх предыдущих слоёв кажется, что тут уже нечего собирать.
Кажется зря.
Порядок HTTP-заголовков уникален для каждого браузера. Chrome ставит Host, потом Connection, потом Accept. Firefox расставляет иначе. Стандарт порядок не регламентирует: каждый движок решает сам. JA4H хеширует этот порядок в отпечаток. Изменить порядок заголовков из расширения невозможно: они формируются сетевым стеком до вызова любых расширений.
Accept-Language как индикатор. Chrome выставляет q=0.9 для вторичных языков. Некоторые антидетекты ставят q=0.8. Разница в одну десятую. Хватает для мгновенной детекции. В разведке это называют канарейкой: мелкая деталь, которая сжигает всю легенду.
Client Hints: волк в овечьей шкуре
User-Agent Client Hints позиционировались как замена строки User-Agent, более приватная, более контролируемая. На деле: исследование KU Leuven, Wpes 2023. Client Hints обнаружены на 59.2% из топ-100К сайтов. 93.8% обращений к ним идут от трекинговых и рекламных скриптов. 91.6% данных уходят на внешние серверы. Инструмент для приватности, который в девяти случаях из десяти служит слежке. Оруэлл бы не удивился.
WHOX проверяет совпадение JA4 с User-Agent в сигнале C12. TLS Client Hello говорит Chrome 120. User-Agent подтверждает Chrome 120. Но JA4-хеш не бьётся с эталоном. Кто-то подделал визитку, но забыл сменить акцент. Так палятся антидетекты, боты и скреперы.
Hpack: память, которая сливает
HTTP/2 сжимает заголовки через Hpack. Динамическая таблица наполняется данными из предыдущих запросов. Первый запрос: все заголовки целиком. Второй: часть через индексы. Третий: ещё больше индексов. К десятому запросу состояние таблицы у двух разных пользователей полностью разъехалось, потому что они кликали разные ссылки. Сервер видит, какие индексы вы используете, и может восстановить историю навигации.
Публикаций на эту тему в сообществе фингерпринтинга нет. Механизм работает на каждом HTTP/2-соединении в мире прямо сейчас. Встроенная функция протокола, которую никто не превратил в оружие. Ключевое слово пока. Мы тут все взрослые люди.
Слой 4+: QUIC/HTTP/3
38.1% сайтов по W3Techs на февраль 2026 работают через QUIC, а по объёму трафика гораздо больше из-за Google, YouTube и Cloudflare. Новый протокол, новые отпечатки.
QUIC Initial-пакет несёт TLS 1.3 Client Hello. Формально зашифрованный, но ключ шифрования вычисляется из публичного Connection ID. Любой, кто читал спецификацию, может прочитать ваш Client Hello. Замок, к которому ключ приклеен скотчем к двери.
VisQUIC, arXiv 2024-2025: 100 000+ трейсов с 44 000 сайтов. Точность определения HTTP/3-ответов по зашифрованному QUIC: 97%. Классификаторы, обученные на TCP, ломаются на 96% QUIC-визитов. Два мира. Два набора отпечатков. Двойная работа для того, кто хочет остаться невидимым.
0-RTT: куки на уровне транспорта
QUIC поддерживает 0-RTT resumption. Браузер шлёт данные в первом же пакете, используя session ticket от предыдущего соединения. Быстро. Удобно. И по сути, трекинговая кука, впаянная в транспортный слой, о которой пользователь не знает и которую не стереть кнопкой Очистить данные.
Session ticket связывает текущее соединение с предыдущим. Сервер знает, что вы тот же клиент. Не по кукам. Не по IP. По криптографическому токену в первом пакете. Почистили куки? Открыли инкогнито? Сменили профиль? Session ticket живёт этажом ниже. Туда кнопка Очистить не добирается.
Технология, созданная ради скорости, стала инструментом привязки. Чем быстрее соединение, тем тоньше приватность. Компромисс, о котором пользователю забыли рассказать. Забыли или решили, что и так сойдёт.
Почему антидетекты бессильны
Антидетект-браузеры живут в мире JavaScript. Подменяют canvas, WebGL, navigator.userAgent, шрифты. Мир DOM и API. Привычный, уютный, управляемый.
Сетевой стек это другой мир. Подвал, куда JavaScript не спускается.
JA4 антидетекта никогда не совпадает с JA4 заявленного браузера. Самые частые палевные паттерны:
- Chrome UA и JA4 от curl. Кто-то взял curl, выставил User-Agent, и на этом успокоился. Как если бы на маскарад надели только шляпу пилота. Шляпа верная. Всё остальное не то.
- Chrome UA и HTTP/2 SETTINGS от Firefox. Антидетект на базе Firefox с подменённым User-Agent. Сетевой стек всё ещё Firefox. Акцент выдаёт.
- Windows UA и macOS TTL. Подмена ОС в заголовках, но TTL в IP-пакете показывает настоящую платформу. Новый паспорт, старая татуировка.
curl-impersonate существует именно потому, что нельзя настроить curl на имитацию Chrome. Нужен полный форк с модифицированным TLS и HTTP/2. И даже после этого совпадение неидеальное.
dMAP, NDSS 2025: обфусцированный прокси-трафик ловят с точностью 95% через кросс-слойный анализ RTT. Сервер замеряет время между TCP ACK и HTTP-ответом. Прокси добавляет хоп. Хоп добавляет миллисекунды, которые физически невозможно спрятать. Подделать TLS можно. Подделать User-Agent можно. Подделать скорость света нельзя.
WHOX ловит это в четырёх сигналах: A18, C12, C09, A06. Четыре проверки, четыре слоя, ни одна не требует JavaScript.
Полная картина: что сервер знает за 100 мс
| Время | Слой | Что узнаёт сервер | Инструмент |
|---|---|---|---|
| 0-1 мс | TCP SYN | ОС, VPN/туннель, оператор связи | JA4T, p0f, eBPF |
| 20-50 мс | TLS Client Hello | Браузер, версия, TLS-стек | JA4 |
| 50-80 мс | HTTP/2 SETTINGS | Диалект HTTP/2, автоматизация | Akamai H2 FP |
| 80-100 мс | HTTP-заголовки | Порядок заголовков, язык, Client Hints | JA4H |
| 100+ мс | QUIC | QUIC transport params, 0-RTT | JA4Q, VisQUIC |
К моменту, когда JavaScript получит управление, сервер прошёл пять этапов идентификации. Расширение браузера не участвовало ни в одном. Оно даже не в курсе, что они были.
FAQ
VPN защищает от TCP-фингерпринтинга? VPN меняет IP-адрес. TCP-отпечаток формируется вашей ОС до того, как пакет попадёт в туннель. Window Size, TCP Options, Window Scale остаются вашими. Единственное, что VPN меняет: MSS, потому что шифрование его уменьшает. И это уменьшение само по себе сигнал. VPN не защищает от TCP-фингерпринтинга. VPN добавляет к нему новые данные. Пришли лечиться, ушли с диагнозом.
Tor подменяет TCP/TLS-отпечатки? Tor Browser стандартизирует TLS Client Hello для всех пользователей: у всех одинаковый отпечаток. TCP проходит через три ноды и выходит с параметрами exit-ноды, не вашими. Задача решена. Ценой скорости, удобства и терпения, которого хватает у доли процента пользователей.
Как JA4 справляется с рандомизацией расширений? Сортирует перед хешированием. Неважно, в каком порядке Chrome их отправил: после сортировки порядок стабилен. 99% точности по данным Peakhour. Колоду можно тасовать сколько угодно. Крупье всё равно знает расклад.
Антидетекты могут подделать HTTP/2 SETTINGS? В теории да, если форкнуть Chromium и переписать сетевой код. На практике ни один массовый антидетект на это не пошёл. curl-impersonate пошёл, и результат: полный форк curl с отдельными сборками под каждый целевой браузер. Это не установить расширение. Это переложить фундамент.
JA4 Signals от Cloudflare: что это? Агрегация всего глобального трафика за последний час. Для каждого JA4-отпечатка: какие user agents с ним обычно идут, из каких стран, с какой частотой. Если ваш JA4 совпадает с отпечатком, типичным для Python-ботов, Cloudflare об этом знает. Не из вашего поведения. Из статистики планеты. Личное дело, собранное из средних по больнице.
Читайте также
- Первые 100 миллисекунд: что сервер знает до загрузки страницы
- Как ловят антидетект-браузеры
- WebGPU, QUIC, eBPF: будущее фингерпринтинга
- Что реально работает для защиты приватности
- Проверьте свой отпечаток —
WHOX - Отличаем настоящие сигналы от сфабрикованных. Проверьте свой отпечаток на whox.com и узнайте какие сигналы утекают из вашего браузера и насколько вы уникальны.
Похожие статьи
«Не раскрывай себя»: разбираем систему маскировки AI-авторства по винтикам
Утёк исходный код Claude Code. Мы разобрали архитектуру маскировки: семь взаимосвязанных систем от Undercover Mode до антидистилляции, проверили на 28 публичных PR от сотрудников Anthropic и составили карту каждого слоя, который система покрывает и каждого, который нет.
ИсследованияЛожь рандомизации: все Canvas-защиты побеждены
WWW'25 доказала: все 18 расширений и 5 браузеров побеждены. Canvas-шум > не защита, а маркер. Ноль рабочих решений.
ИсследованияКарта энтропии: какие сигналы браузера выдают вас
WebGL renderer несёт 6.8 бит энтропии. 13 атрибутов > 60% уникальных. 300+ сигналов > 95%. Ваш отпечаток уникален. Вы это не контролируете.