Отпечаток JA4 — это строка из трёх частей, a_b_c, вычисляемая по TLS ClientHello. Часть a — читаемые метаданные (протокол, версия TLS, SNI, число шифров и расширений, ALPN), часть b — 12-символьный SHA-256 от отсортированного списка шифров, часть c — 12-символьный SHA-256 от отсортированных расширений плюс алгоритмов подписи. Если вы искали b0da82dd1658: это секция c, и она принадлежит Chromium. Точнее, её выдаёт клиент на базе Chromium, когда возобновляет сессию TLS 1.3 и при этом всё ещё использует старый кодпоинт расширения ALPS. Дальше на этой странице — как мы это установили и как расшифровать любую строку JA4 самостоятельно.
Как устроен отпечаток JA4: формат a_b_c
Официальная техническая спецификация JA4 от FoxIO определяет отпечаток как один читаемый префикс и два усечённых хеша, соединённых подчёркиваниями. Значения GREASE везде игнорируются, все хеши — в нижнем регистре.
| Секция | Символов | Что кодирует | Возможные значения |
|---|---|---|---|
| a | 1 | Транспорт | t = TLS поверх TCP, q = QUIC, d = DTLS |
| a | 2 | Старшая версия TLS (из supported_versions, если есть, иначе версия ClientHello) | 13, 12, 11, 10, s3, d2, 00 = неизвестна… |
| a | 1 | Есть ли SNI? | d = домен (SNI отправлен), i = без SNI (обычно подключение к голому IP) |
| a | 2 | Число шифронаборов (без GREASE) | 00–99 |
| a | 2 | Число расширений (без GREASE, включая SNI и ALPN) | 00–99 |
| a | 2 | Первый и последний символ первого значения ALPN | h2, h1 (http/1.1), h3, 00 = без ALPN |
| b | 12 | SHA-256 от шифронаборов в виде 4-символьного hex, отсортированных и соединённых запятыми | 000000000000, если их нет |
| c | 12 | SHA-256 от расширений (отсортированных, без SNI 0000 и ALPN 0010) + _ + алгоритмы подписи в порядке передачи | 000000000000, если их нет |
На двух деталях часто спотыкаются. Во-первых, число расширений в части a включает SNI и ALPN, а хеш расширений в части c их исключает, поэтому один и тот же клиент даёт одинаковую c независимо от того, подключается он к имени хоста или к IP. Во-вторых, алгоритмы подписи хешируются в том порядке, в каком их отправил клиент, без сортировки, так что клиент, переставивший свои предпочтения подписей, меняет c даже при идентичных расширениях.
Разбираем t13d1516h2_8daaf6152771_… по частям
t: TLS поверх TCP, а не QUIC.13: клиент предлагает TLS 1.3 как старшую версию.d: присутствовало расширение SNI, то есть клиент подключался к доменному имени.15: 15 шифронаборов после удаления GREASE.16: 16 расширений после удаления GREASE, с учётом SNI и ALPN.h2: первое значение ALPN —h2, то есть клиент предпочитает HTTP/2.8daaf6152771: хеш вот этой отсортированной строки шифров, который можно воспроизвести любым инструментом SHA-256:
printf '%s' "002f,0035,009c,009d,1301,1302,1303,c013,c014,c02b,c02c,c02f,c030,cca8,cca9" \
| sha256sum | cut -c1-12
# 8daaf6152771
Этот список — три шифронабора TLS 1.3 плюс двенадцать устаревших наборов TLS 1.2 из Chrome. Каждая проверенная нами сборка Chromium, от примеров FoxIO до headless Chrome 148, по-прежнему даёт 8daaf6152771. Так что секция b говорит «TLS-стек семейства Chromium» и почти ничего — о версии. Различия между версиями видны в c.
Небольшая оговорка для тех, кто читает спецификацию внимательно: в её кратком описании алгоритма приведено t13d1516h2_8daaf6152771_b186095e22b6, а её разобранный пример хешируется в e5627efa2ab1. Мы пересчитали пример и получили e5627efa2ab1, так что первую строку считайте иллюстрацией.
Что означает b0da82dd1658
b0da82dd1658 — секция c отпечатка JA4 от Chromium. Это хеш вот этой точной строки:
0005,000a,000b,000d,0012,0017,001b,0023,0029,002b,002d,0033,4469,fe0d,ff01_0403,0804,0401,0503,0805,0501,0806,0601
Проверить можно самостоятельно:
printf '%s' "0005,000a,000b,000d,0012,0017,001b,0023,0029,002b,002d,0033,4469,fe0d,ff01_0403,0804,0401,0503,0805,0501,0806,0601" \
| sha256sum | cut -c1-12
# b0da82dd1658
Клиента выдают три расширения из этого списка:
0029(pre_shared_key). Это возобновление сессии TLS 1.3. Оно появляется, только когда у клиента уже есть тикет от предыдущего подключения к тому же серверу. Определено в RFC 8446 §4.2.11. Без него тот же браузер хешируется в02713d6af862.4469(ALPS, исходный кодпоинт). Application-Layer Protocol Settings — расширение Chrome. BoringSSL добавил для него новый кодпоинт в сентябре 2023 года (0x44cd), и современный Chrome отправляет новый. Значит,4469указывает на старую сборку Chromium или на инструмент, копирующий такую сборку.fe0d(Encrypted Client Hello). Chrome отправляет GREASE-расширение ECH в обычных соединениях.
В собственном файле FoxIO ja4plus-mapping.csv строки t13d1517h2_8daaf6152771_b0da82dd1658 и t13i1516h2_8daaf6152771_b0da82dd1658 помечены как «Chromium Browser». Арифметика префикса сходится: 15 хешируемых расширений плюс SNI плюс ALPN дают 17 с SNI (d) и 16 без него (i). Это же выявляет несоответствие, которое многократно повторяется в интернете. Строка вроде t13d1516h2_8daaf6152771_b0da82dd1658 не может получиться из одного реального ClientHello: при наличии и SNI, и ALPN эти 15 хешируемых расширений обязаны дать счётчик 17.
Мы также воспроизвели это значение напрямую. 3 октября 2026 года curl_cffi 0.16.3 с impersonate="chrome131" отправил первый запрос к tls.peet.ws как t13d1516h2_8daaf6152771_02713d6af862. Второй запрос в той же сессии, который возобновил TLS-сессию, вернулся как t13d1517h2_8daaf6152771_b0da82dd1658. Короче говоря, b0da82dd1658 означает «ClientHello в стиле Chromium, старый кодпоинт ALPS, возобновлённая сессия». Под это подпадают настоящие старые сборки Chrome, Edge, Brave и Opera, встроенный Chromium и библиотеки имперсонации, привязанные к профилю Chrome до смены кодпоинта. Один только JA4 их не различает.
Справочная таблица: реальные значения JA4 по клиентам
Значения ниже взяты только из двух источников: опубликованных примеров и mapping-файла FoxIO и наших собственных захватов на tls.peet.ws от 3 октября 2026 года (версии указаны). Значения библиотек сильно зависят от TLS-бэкенда и опций его сборки, поэтому строки с библиотеками считайте примерами, а не универсальными константами. Строки, которые мы не смогли проверить, включая собственный захват настоящих Firefox и Safari, мы не включили.
| Клиент | JA4 | Источник |
|---|---|---|
| Headless Chrome 148 (Linux), новое соединение | t13d1516h2_8daaf6152771_d8a2da3f94cd | Наш захват, Playwright Chromium |
| Тот же браузер, возобновлённая сессия | t13d1517h2_8daaf6152771_b6f405a00624 | Наш захват |
| Chromium, старый кодпоинт ALPS, новая / возобновлённая | t13d1516h2_8daaf6152771_02713d6af862 / t13d1517h2_8daaf6152771_b0da82dd1658 | Mapping CSV от FoxIO; воспроизведено через curl_cffi chrome131 |
| Chrome поверх QUIC | q13d0312h3_55b375c5d22e_178839b6cec1 | README FoxIO |
| Mozilla Firefox (версия не указана) | t13d1715h2_5b57614c22b0_7121afd63204 | Mapping CSV от FoxIO |
| Safari (версия не указана) | t13d2014h2_a09f3c656075_14788d8d241b | Mapping CSV от FoxIO |
| curl 8.5.0 / OpenSSL 3.0.13 (Ubuntu) | t13d3112h2_e8f1e7e78f70_b26ce05bbdd6 | Наш захват; совпадает на tls.peet.ws, BrowserLeaks и Scrapfly |
| Python requests 2.31 / urllib3 2.0.7, OpenSSL 3.0.13 | t13d3112h1_e8f1e7e78f70_b26ce05bbdd6 | Наш захват |
| Go 1.24.1 net/http (клиент по умолчанию) | t13d1311h2_f57a46bbacb6_e7c285222651 | Наш захват |
curl_cffi 0.16.3, impersonate="chrome146" | t13d1516h2_8daaf6152771_d8a2da3f94cd | Наш захват |
curl_cffi 0.16.3, impersonate="firefox147" | t13d1717h2_5b57614c22b0_3cbfd9057e0d | Наш захват |
curl_cffi 0.16.3, impersonate="safari2601" | t13d2013h2_a09f3c656075_7f0f34a4126d | Наш захват |
Закономерности важнее отдельных строк:
- Секция c часто идентифицирует TLS-библиотеку, а не приложение. curl и Python на одной сборке OpenSSL 3 делят
b26ce05bbdd6. В mapping-файле FoxIO есть запись для Python с другим префиксом, но той же c. Go-клиенты в файле FoxIO делятe7c285222651с нашим захватом Go 1.24. - requests показывает
h1. urllib3 2.x объявляет в ALPN толькоhttp/1.1, поэтому секция a сообщает серверу, что он говорит не с браузером, ещё до чтения любого заголовка. - Обычную библиотеку легко распознать по одним счётчикам. 31 шифр (дефолт OpenSSL) или 13 шифров с 11 расширениями (Go) совсем не похожи на схему 15/16, которую отправляет любая актуальная сборка Chromium.
- Возобновление сессии меняет c у любого браузера. В наших захватах через curl_cffi Firefox на возобновлённых сессиях переходит с 17 на 18 расширений, а Safari — с 13 на 14. Правило обнаружения, которое разрешает только значение для нового соединения, будет ошибаться на реальных вернувшихся посетителях.
Строка Chrome будет продолжать меняться. Новейший профиль curl_cffi chrome150 добавляет три алгоритма подписи — 0904, 0905 и 0906. Это кодпоинты ML-DSA из черновика IETF, и они превращают c в 806a8c22fdea. Подтвердить это на стабильной сборке Chrome 150 мы не смогли, поэтому считайте значение предварительным, а не справочным.
Почему JA4 сортирует шифры и расширения
JA4 сортирует шифры и расширения потому, что Chrome намеренно рандомизирует порядок расширений, и чувствительный к порядку отпечаток (JA3) перестал быть стабильным. Chrome выпустил перестановку расширений TLS ClientHello примерно в Chrome 110 в начале 2023 года. Цель была в том, чтобы серверы и промежуточные устройства перестали полагаться на фиксированную раскладку. Fastly измерил эффект: поскольку JA3 хеширует расширения в порядке передачи, одна установка Chrome даёт новый JA3 практически при каждом соединении.
JA4 решает это сортировкой перед хешированием. FoxIO опубликовал его в составе набора JA4+ в сентябре 2023 года (перепубликация в APNIC). Сейчас его отдают Cloudflare Bot Management, AWS CloudFront и WAF, Google Cloud Armor, Fastly, Akamai и другие, перечисленные в README FoxIO.
Для скраперов это палка о двух концах. Перемешивание порядка расширений больше не меняет отпечаток, так что этот трюк мёртв. Значение по-прежнему имеют набор шифров, набор расширений и порядок алгоритмов подписи. На практике это значит использовать TLS-стек, которым пользуется настоящий браузер, или библиотеку, которая близко его копирует. Если нужен вид в исходном порядке (например, для сравнения с JA3), спецификация определяет JA4_o и сырые варианты JA4_r / JA4_ro. BrowserLeaks возвращает все четыре. Подробнее о JA3 — в нашем разборе TLS-фингерпринтинга.
Семейство JA4+: JA4S, JA4H, JA4X, JA4T
JA4 — лишь один метод из более широкого набора. Остальные смотрят на сервер, HTTP-уровень, сертификаты и TCP, и распространяются под другой лицензией.
| Метод | Что отпечатывает | Формат вкратце |
|---|---|---|
| JA4S | ServerHello сервера | протокол + версия + число расширений + ALPN, затем выбранный шифр, затем хеш расширений сервера |
| JA4H | HTTP-запрос | метод (ge, po…), версия (11, 20), cookie c/n, referer r/n, число заголовков, первые 4 символа Accept-Language; затем хеши имён заголовков в порядке следования, отсортированных имён cookie и отсортированных пар имя=значение cookie |
| JA4X | Сертификат X.509 | хеши OID в RDN издателя, OID в RDN субъекта и OID расширений (как сертификат собран, а не его значения) |
| JA4T | TCP SYN | размер окна, TCP-опции по порядку, MSS, масштаб окна, например 64240_2-1-3-1-1-4_1460_8 для Windows 11 |
Форматы взяты из технических диаграмм FoxIO и эталонной реализации на Python. Для скрапинга важнее всего JA4H. Его секция b хеширует имена заголовков в порядке отправки, поэтому клиент, отправляющий заголовки Chrome не в том порядке, заметен, даже если все значения верны. Связанные сигналы порядка SETTINGS и псевдозаголовков разобраны в нашей статье об HTTP/2-фингерпринтинге. JA4T выдаёт ОС: SYN от Linux-сервера не похож на Windows, что бы ни говорил User-Agent.
Лицензирование
Согласно разделу о лицензировании в репозитории, JA4 (отпечаток TLS-клиента) распространяется под BSD 3-Clause, как и JA3, и FoxIO заявляет, что не имеет на него патентных притязаний. JA4S, JA4L, JA4LS, JA4H, JA4X, JA4SSH, JA4T, JA4TS, JA4TScan, JA4D, JA4D6 и другие методы «JA4+» находятся в процессе патентования и лицензируются по FoxIO License 1.1. Эта лицензия разрешает внутреннее и академическое использование, но вендору, продающему JA4+-фингерпринтинг в составе продукта, нужна OEM-лицензия.
QUIC и HTTP/3: что говорит префикс q
JA4, начинающийся с q, вычислен по пакету QUIC Initial — то есть клиент устанавливал HTTP/3. QUIC несёт ClientHello TLS 1.3 внутри своих фреймов CRYPTO. Ключи защиты Initial-пакета выводятся из Destination Connection ID, который выбирает клиент (RFC 9001 §5.2), поэтому любой наблюдатель на пути или пограничный сервер может его расшифровать и снять отпечаток ClientHello точно так же, как поверх TCP.
QUIC-отпечаток Chrome сильно отличается от TCP-шного: q13d0312h3_55b375c5d22e_178839b6cec1 в примере FoxIO. Это 3 шифра (только TLS 1.3, поскольку QUIC запрещает старые версии) и ALPN h3. Для автоматизации это важно: браузеры переходят на HTTP/3, как только сайт его объявляет, а большинство HTTP-клиентов не переходит никогда. Задокументированные Cloudflare JA4 Signals включают значение h2h3_ratio_1h — долю трафика с данным JA4, приходящего по HTTP/2 по сравнению с HTTP/3. TLS-отпечаток «Chrome», который на сайте с HTTP/3 никогда не появляется поверх QUIC, — статистический выброс. В README curl_cffi указано, что имперсонация отпечатка HTTP/3 поддерживается начиная с v0.15.0.
Как посмотреть свой JA4
Быстрее всего проверить через эхо-сервис, который читает ваш ClientHello и возвращает отпечаток. Эти три вернули JA4 в наших тестах и совпали друг с другом байт в байт:
- tls.peet.ws/api/all: JSON с
tls.ja4,tls.ja4_r, JA3, HTTP/2-отпечатком Akamai иhttp_version. - tls.browserleaks.com/json: JSON с
ja4,ja4_r,ja4_o,ja4_ro. - Инструмент JA3/JA4 от Scrapfly, чей API по адресу
tools.scrapfly.io/api/fp/ja3возвращаетja4иja4_r.
curl -s https://tls.peet.ws/api/all | python3 -c \
"import sys, json; d = json.load(sys.stdin); print(d['http_version'], d['tls']['ja4'])"
Запускайте ту же проверку через свой прокси, а не только со своего ноутбука. Прямой прокси, туннелирующий через CONNECT, пропускает ваш ClientHello нетронутым, но прокси с перехватом TLS, корпоративное промежуточное устройство или некоторые слои SDK подставят свой. Например, с резидентным выходом ProxyHat:
curl -s -x http://USERNAME:PASSWORD@gate.proxyhat.com:8080 https://tls.peet.ws/api/all
Wireshark и tshark
Wireshark вычисляет JA4 нативно начиная с версии 4.2.0, в поле фильтра отображения tls.handshake.ja4 (и tls.handshake.ja4_r), согласно справочнику полей TLS. Плагин JA4+ от FoxIO (Wireshark 4.4.0 или новее) добавляет остальную часть набора в пространстве ja4.*, например ja4.ja4s, ja4.ja4h и ja4.ja4t. Чтобы извлечь отпечатки из захвата:
tshark -r capture.pcapng -Y "tls.handshake.ja4" -T fields \
-e ip.dst -e tls.handshake.extensions_server_name -e tls.handshake.ja4
Захватывайте трафик на машине, где вы контролируете клиента. Чтобы снять отпечаток HTTPS-трафика headless-браузера, запустите его локально и захватывайте на loopback- или исходящем интерфейсе. ClientHello не зашифрован, поэтому для JA4 ключи TLS не нужны. Для JA4H по HTTPS — нужны.
Что это значит на практике: заголовки должны соответствовать рукопожатию
Смена User-Agent не меняет ваш JA4. Python-скрипт, отправляющий User-Agent от Chrome, всё равно предъявляет в рукопожатии t13d3112h1_e8f1e7e78f70_b26ce05bbdd6 ещё до того, как прочитан хоть один заголовок. Такое несоответствие (заявляет Chrome, договаривается как OpenSSL, просит HTTP/1.1) — одна из самых дешёвых проверок, которые может выполнить edge. И именно для его поимки строятся базы JA4.
Есть два распространённых способа это исправить. У обоих есть пределы.
- curl_cffi (Python-биндинги к curl-impersonate) собирает ClientHello и фреймы HTTP/2 под указанный профиль браузера:
requests.get(url, impersonate="chrome"). В наших захватах его актуальные профили Chrome дали тот же JA4, что и настоящий headless Chrome 148. Сессии и прокси разобраны в нашем руководстве по curl_cffi. - uTLS для Go заменяет ClientHello из
crypto/tlsна «попугая» вродеtls.HelloChrome_Autoчерезtls.UClient(conn, &config, helloID). Его README прямо предупреждает, что имитация может быть неидеальной и не выходит за пределы ClientHello. В нашем пошаговом руководстве по uTLS в Go показано, как подключить его кnet/http.
Чего имперсонация не решает
Совпадающий JA4 проводит вас только через первый фильтр.
- JA4 должен соответствовать заявленной версии браузера: User-Agent Chrome 148 со старым кодпоинтом ALPS (
b0da82dd1658) — само по себе небольшое несоответствие. - Порядок заголовков в JA4H тоже должен совпадать.
- JA4T и данные об IP раскрывают ОС хоста и сеть.
- JavaScript-челленджи в HTTP-клиенте никогда не выполняются.
- Поведение (частота запросов, схема навигации) оценивается отдельно.
Выбирайте профиль, соответствующий отправляемому User-Agent, держите сессии живыми, чтобы возобновление выглядело естественно, и следите, чтобы выходной IP был правдоподобен для такого трафика. Резидентный выход исправляет слой сетевой репутации, а не слой TLS. Проверяйте отпечаток через прокси, как показано выше.
И наконец: разбираться в отпечатках стоит для того, чтобы легитимная автоматизация была честной и предсказуемой, а не чтобы прорываться на сайт, который решил отказать автоматизированному доступу. Соблюдайте robots.txt и условия использования там, где они применимы, и помните, что сбор персональных данных влечёт юридические обязательства, с которыми идеальный JA4 ничего не делает.






