Как работает TLS-фингерпринтинг, как JA3 и JA4 выявляют ботов и перехватывающие прокси на сетевом уровне и как проверить собственное TLS-рукопожатие.
Каждое HTTPS-соединение начинается с рукопожатия. До того как передаётся хоть байт прикладных данных, ваш браузер и сервер согласовывают, какие алгоритмы шифрования использовать, — и сам способ, которым браузер проводит это согласование, создаёт отпечаток, столь же характерный, как хеш Canvas или WebGL. TLS-фингерпринтинг извлекает эту подпись из рукопожатия, чтобы идентифицировать клиентское программное обеспечение, отправившее запрос, — без каких-либо JavaScript или cookie. На уровень ниже, ещё до того как начнётся TLS, TCP/IP-фингерпринтинг уже раскрыл вашу операционную систему по TCP-рукопожатию; TLS-фингерпринтинг подхватывает на криптографическом уровне.
Ключевые выводы
- TLS ClientHello — это и есть отпечаток. Когда ваш браузер открывает HTTPS-соединение, он отправляет ClientHello, перечисляя поддерживаемые наборы шифров, расширения и эллиптические кривые — в порядке, продиктованном TLS-библиотекой, а не вами.
- JA3 хеширует пять полей ClientHello в 32-символьную MD5-строку; одна и та же сборка браузера на одной и той же ОС всегда даёт один и тот же хеш JA3.
- JA4 улучшает JA3, предлагая читаемый человеком, сортируемый формат, устойчивый к рандомизации GREASE и переупорядочиванию расширений.
- Серверы сочетают TLS-отпечатки с заголовками User-Agent, чтобы поймать поддельных ботов: запрос, претендующий быть Chrome, но несущий рукопожатие Python
requests, — немедленный красный флаг. - Изменить TLS-отпечаток можно только заменив или перенастроив саму TLS-библиотеку — настройки браузера и расширения до него не добираются.
Спешите? Проверьте собственный живой TLS-отпечаток — ваш JA4, набор шифров и ClientHello, считанные прямо из этого соединения.
Что такое TLS-фингерпринтинг?
HTTPS-трафик зашифрован, но процесс его установки — нет. Для создания зашифрованного сеанса клиент отправляет сообщение ClientHello открытым текстом, содержащее:
- Устаревшее поле версии TLS (как правило,
0x0303; клиент TLS 1.3 сигнализирует о своей реальной максимальной версии в расширенииsupported_versions, которое JA3 не читает) - Список наборов шифров, которые он готов использовать, в порядке предпочтения
- Список расширений (указание имени сервера, поддерживаемые группы, совместное использование ключей, ALPN и другие)
- Поддерживаемые эллиптические кривые (именованные группы) для обмена ключами
- Поддерживаемые форматы точек эллиптических кривых
Эти поля определяются TLS-библиотекой, скомпонованной в приложение, — а не пользователем, операционной системой или посещаемым доменом. Стек BoringSSL в Chrome, NSS в Firefox, Secure Transport в Safari и OpenSSL-биндинги Python — каждый генерирует свой узнаваемый ClientHello. TLS-фингерпринтинг считывает эти различия и превращает их в идентификатор.
Стандарт TLS 1.3 (RFC 8446) предписывает набор обязательных расширений, но оставляет порядок необязательных расширений и выбор наборов шифров из допустимого множества на усмотрение реализации — именно там и живут отпечатки.
JA3: первый широко принятый отпечаток
JA3 был опубликован инженерами Salesforce (Джоном Олтхаусом, Джеффом Аткинсоном и Джошем Аткинсом) в 2017 году как простой и развёртываемый способ создавать отпечатки TLS-клиентов на сетевом уровне, не выполняя никакого кода на клиенте. Он работает, извлекая пять полей из ClientHello и соединяя их значениями, разделёнными запятыми:
TLSVersion,Ciphers,Extensions,EllipticCurves,EllipticCurvePointFormats
Поля с несколькими значениями соединяются дефисами. Результирующая строка затем хешируется MD5, образуя 32-символьный отпечаток — например, 769a07eb7f17701dd0ad09b9d04ee785.
Ряд свойств делает JA3 одновременно полезным и ограниченным:
Почему работает: Хеш стабилен между сеансами. Одна и та же версия Chrome на одной и той же ОС всегда выдаёт одинаковый JA3, поскольку TLS-библиотека не меняется между запросами.
Почему ломается: JA3 фиксирует порядок расширений и порядок шифров, поэтому единственная реализация, рандомизирующая порядок, — или обновление браузера, добавляющее один шифр, — сдвигает хеш. MD5-вывод также непрозрачен: из одного лишь отпечатка нельзя понять, принадлежит ли он браузеру или скриптовой библиотеке. Браузер, добавляющий поддержку нового типа расширения, меняет свой JA3, даже если его основная идентичность не изменилась.
JA4: более надёжная замена
JA4 был представлен компанией FoxIO (набор инструментов JA4+, под руководством Джона Олтхауса) в 2023 году, чтобы устранить ломкость JA3. Ключевое изменение в дизайне — сортировка: наборы шифров и расширения сортируются по числовым (шестнадцатеричным) значениям перед хешированием, поэтому их переупорядочивание не меняет отпечаток. Значения GREASE — зарезервированные фиктивные кодовые точки из фиксированного набора, определённого в RFC 8701, которые браузеры отправляют, чтобы промежуточные устройства не окостенели, отвергая нераспознанные поля, — удаляются перед хешированием, поэтому обновление Chrome, обновляющее выбор GREASE, не аннулирует существующие подписи.
Отпечаток JA4 имеет читаемый человеком префикс и два хешированных компонента:
t13d1516h2 _ 8daaf6152771 _ e5627ecdbe6c
│ │ └── усечённый SHA-256 отсортированных расширений
│ │ (GREASE и SNI удалены) плюс алгоритмы подписи
│ └────────────────── усечённый SHA-256 отсортированных наборов шифров
└───────────────────────────────── читаемый префикс: t = TLS, 13 = TLS 1.3,
d = SNI присутствует, 15 = количество шифров,
16 = количество расширений, h2 = ALPN (HTTP/2)
Уже по одному префиксу видно версию TLS, наличие SNI, количество наборов шифров и расширений, а также согласованный ALPN — что позволяет рассуждать об отпечатке без базы данных. Два хешированных суффикса (список шифров, затем список расширений плюс алгоритмы подписи) сужают идентификацию до конкретной реализации.
JA3 и JA4: сравнение
| Свойство | JA3 | JA4 |
|---|---|---|
| Формат вывода | MD5-хеш (32 символа, непрозрачный) | Читаемый префикс + два хеша |
| Чувствительность к порядку | Да — переупорядочивание меняет хеш | Нет — значения сортируются перед хешированием |
| Обработка GREASE | Включается, сдвигает хеши при обновлении | Удаляется перед хешированием |
| Видимость версии TLS | Нет | Да (в префиксе) |
| Год появления | 2017 | 2023 |
На практике инструменты безопасности и CDN-сети всё чаще начинают логировать оба значения бок о бок.
Сейчас под влиянием обоих алгоритмов оказывается ещё одно поле: постквантовый обмен ключами. Гибридные группы вроде X25519MLKEM768 появляются в расширениях supported_groups и key_share массовых браузеров, и поскольку JA4 сортирует значения перед хешированием, а JA3 — нет, эти два алгоритма поглощают это изменение совершенно по-разному — подробности в статье как ML-KEM меняет отпечаток вашего ClientHello.
Теперь, когда вы умеете отличать JA3 от JA4, вот живые TLS-метаданные, которые наш граничный узел наблюдал для вашего текущего соединения, — версия, набор шифров и (где доступно) хеш JA3/JA4 — без какого-либо сохранения:
Ваш живой TLS-отпечаток
Считано из ClientHello этого соединения — ничего не сохраняется.
Читаем ваше TLS-рукопожатие…
Хеши JA3/JA4 требуют глубокой инспекции пакетов на границе сети; показаны те поля, которые раскрывает это соединение.
Сигнал, за которым стоит следить, — это согласованность: совпадает ли ваш отпечаток с браузером, которым ваш User-Agent себя объявляет? Несоответствие — скажем, рукопожатие, похожее на Python requests, за User-Agent с Chrome, — означает, что что-то на вашем сетевом пути (корпоративный прокси, устройство безопасности или инспекционный инструмент) переписывает ваше рукопожатие.
Как серверы используют TLS-отпечатки
Обнаружение ботов и автоматизации
Наиболее распространённое применение — поймать инструменты автоматизации, которые выдают себя за браузеры. Библиотека requests Python, net/http Go, curl и Scrapy — у каждого своё характерное TLS-рукопожатие. Когда запрос приходит с заголовком User-Agent: Mozilla/5.0 (Chrome ...), но JA3-хеш совпадает с OpenSSL-биндингами Python, — несоответствие является немедленным свидетельством подделки.
Это сетевой аналог проверки несоответствия отпечатков, описанной в руководстве по методам обнаружения ботов. Принцип тот же: если два наблюдаемых слоя противоречат друг другу, один из них лжёт. TLS-фингерпринтинг имеет одно особое преимущество перед JavaScript-проверками — он работает на сыром TCP-потоке до того, как страница загружается, что делает его невидимым для бота. Серверы, проверяющие также HTTP/2-отпечаток соединения — значения SETTINGS, прирост окна управления потоком и порядок псевдозаголовков, — добавляют второе сетевое измерение: бот, успешно имитирующий TLS-рукопожатие Chrome, всё равно может быть разоблачён HTTP/2-фреймами, которые его библиотека отправляет до первого запроса.
Обнаружение VPN и прокси
Обычный туннельный VPN (WireGuard, OpenVPN, IPSec) не меняет ваш TLS-отпечаток: ваш браузер по-прежнему устанавливает собственное TLS-соединение, а VPN лишь оборачивает этот трафик на IP-уровне, поэтому целевой сервер видит настоящий ClientHello браузера. TLS-фингерпринтинг на самом деле ловит перехват. Прокси HTTPS-инспекции — и VPN-приложения, которые завершают TLS за вас, — используют собственные TLS-библиотеки, генерируя рукопожатия, отличающиеся от любого обычного браузера. Корпоративный HTTPS-прокси, например, повторно шифрует трафик и предъявляет новый ClientHello, который, как правило, соответствует корпоративному средству безопасности, а не браузеру. Системы обнаружения могут пометить это как свидетельство того, что соединение перехватывается. Читайте о полной картине в статье как сайты определяют VPN и прокси — помимо TLS-отпечатков там рассматриваются IP-репутация, геонесоответствия и утечки WebRTC.
Мониторинг безопасности
На защитной стороне TLS-фингерпринтинг помогает обнаруживать вредоносное ПО, общающееся с командными серверами. Большинство готового зловреда и эксплойт-фреймворков использует распространённую библиотеку (Python, Go, .NET), создающую узнаваемый JA3, — даже когда доменное имя или IP-адрес меняются от кампании к кампании. Системы обнаружения сетевых вторжений логируют хеши JA3/JA4 и оповещают, когда известная вредоносная подпись появляется в сети.
Проверка собственного TLS-отпечатка
Сравните живой отпечаток выше с браузером, который вы считаете запущенным. Инструмент обнаружения ботов от BrowserInsight выводит его внутрибраузерный аналог — признаки автоматизации и утечки безголового браузера, — тогда как значения JA3/JA4 сетевого уровня требуют серверной проверки, показанной выше, поскольку вычисляются из данных, отправляемых браузером ещё до выполнения какого-либо JavaScript.
Противодействие: как изменить TLS-отпечаток
В отличие от браузерного фингерпринтинга — который можно частично снизить, сменив браузер или включив режим приватности, — изменение TLS-отпечатка требует замены самой TLS-библиотеки, поскольку отпечаток создаётся библиотекой ещё до выполнения какого-либо пользовательского кода.
Использовать целевой браузер напрямую. Самый простой и надёжный способ. Отпечаток Chrome — наиболее ожидаемая подпись в интернете, и использование немодифицированной установки Chrome гарантирует, что ваше TLS-рукопожатие совпадёт с ожиданиями сервера для вашего User-Agent.
Использовать библиотеку имитации TLS. Такие инструменты, как curl-impersonate, переупорядочивают наборы шифров и расширения, точно воспроизводя рукопожатие целевого браузера. Их используют преимущественно операторы скрейпинга, которым нужно пройти TLS-уровневые проверки.
Использовать резидентный прокси, завершающийся настоящим браузером. Некоторые прокси-сервисы пересылают запросы через конвейер, работающий на реальном движке браузера, сохраняя TLS-отпечаток браузера сквозным образом.
Для большинства легитимных пользователей TLS-фингерпринтинг невидим и не требует никаких действий. Он становится актуальным, когда вы запускаете автоматизацию, которая должна выдавать себя за реальный браузер, или хотите понять, почему сетевое устройство или CDN помечает ваш трафик.
Часто задаваемые вопросы
Усложняет ли TLS 1.3 фингерпринтинг?
В определённой мере. TLS 1.3 шифрует больше частей рукопожатия, чем 1.2, включая сертификат сервера, — однако сам ClientHello по необходимости остаётся открытым текстом, поскольку сервер должен прочитать его до появления общих ключей. ClientHello по-прежнему содержит достаточно вариаций для уникальной идентификации клиентов, а JA4 проектировался именно с расчётом на TLS 1.3. Одно появляющееся расширение действительно меняет картину: Encrypted Client Hello (ECH) шифрует конфиденциальный внутренний ClientHello с помощью ключа, публикуемого сервером в DNS. Там, где ECH уже развёрнут (Chrome и Cloudflare поддерживают его с 2023–2024 годов), наблюдатель в сети видит лишь минимальный внешний ClientHello, что существенно ограничивает возможности фингерпринтинга.
Законен ли TLS-фингерпринтинг?
Да, в типичном контексте. Серверам всегда было разрешено читать трафик, адресованный им, а ClientHello — та часть обмена, которая по замыслу протокола обязана быть открытым текстом. Использование этих данных для классификации клиентов ничем не отличается от анализа HTTP-заголовков.
Может ли прокси HTTPS-инспекции скрыть исходный отпечаток?
Нет — он заменяет его другим отпечатком. Прокси, расшифровывающий и повторно шифрующий HTTPS-трафик, предъявляет собственный ClientHello, обычно соответствующий TLS-библиотеке прокси-ПО, а не браузеру пользователя. Системы обнаружения, проверяющие ожидаемые отпечатки, увидят прокси-подпись, которая сама по себе нередко является тревожным сигналом.
Что такое GREASE и почему он влияет на JA3?
GREASE (Generate Random Extensions And Sustain Extensibility) — механизм, определённый в RFC 8701: TLS-реализации анонсируют зарезервированные фиктивные значения — из фиксированного набора кодовых точек GREASE — в своём ClientHello. Цель — гарантировать, что серверы и промежуточные устройства не будут отклонять соединения только потому, что встретили нераспознанное поле, сохраняя тем самым расширяемость протокола. Поскольку JA3 дословно включает эти значения GREASE, обновление Chrome, меняющее выбор GREASE, сдвигает JA3-хеш, даже если функционально ничего не изменилось. JA4 решает эту проблему, удаляя значения GREASE перед хешированием.


