TLS-отпечатки и клиентские сертификаты
Управление TLS ClientHello и предъявление mTLS-сертификатов при replay.
Антибот-платформы оценивают TLS ClientHello ещё до прихода первых прикладных данных: наборы шифров, порядок расширений, ALPN и размещение GREASE складываются в хеши JA3/JA4, по которым фильтруется трафик. Поэтому replay с идеальными заголовками поверх стандартного TLS-стека всё равно проваливается. Replay в Traffic Jam восстанавливает ClientHello захваченного клиента — или профиль браузера/приложения из набора — через uTLS, сохраняет порядок заголовков из захвата и умеет предъявлять mTLS-клиентские сертификаты на любом из транспортов.
Транспорты replay
Каждый replay (откройте запрос в API-лаборатории → Replay) выбирает транспорт:
| Транспорт | ClientHello | Порядок заголовков |
|---|---|---|
native (по умолчанию) — нативный Go-транспорт | Собственный hello используемого Go-тулчейна | Go сортирует заголовки; порядок расходится с захватом |
utls — точный по отпечатку (uTLS) | Восстановлен из профиля (ниже) | Порядок из захвата записывается байт в байт для HTTP/1.1 |
JA3/JA4 нативного транспорта вычисляется один раз за процесс на локальном слушателе с тем же набором ALPN. Транспорт uTLS устанавливает соединение с одноразовым спецификатором HelloCustom, собираемым заново для каждого соединения.
Выбор профиля ClientHello
В диалоге replay установите Transport в Fingerprint-faithful (uTLS), затем выберите профиль ClientHello:
captured— Captured client (session fingerprint), значение по умолчанию для uTLS; восстанавливает hello из TLS-отпечатка захваченной сессии. Если в обмене нет захваченного отпечатка, диалог предупредит, а профиль упадёт при replay — выберите пресет.golang— Go (native stack): нативный hello Go, восстановленный через uTLS; контрольный вариант для A/B-проверки фильтрации по TLS-отпечатку.- Пресеты — реальные hello клиентов из uTLS: Chrome (133, 131, 120, 120-pq, 115-pq, 106, 100, 83, 70), Firefox (120, 105, 102, 99, 65, 55), Safari/iOS (16.0, 14, 13, 12.1, 11.1) и другие (
android-11-okhttp,edge-85,360-7.5,qq-11.1).
JA3/JA4 каждого профиля вычисляется из его спецификатора и отдаётся через GET /api/replay/transports.
Флажок Force HTTP/1.1 переписывает спецификатор так, чтобы в ALPN предлагался только http/1.1, и удаляет HTTP/2-расширение application_settings — тогда порядок заголовков из захвата сохраняется байт в байт.
Как бэкенд воспроизводит ClientHello
При сборке спецификатора из захваченного отпечатка сохраняется то, что наблюдают системы фингерпринтинга, и отбрасывается то, что свежая сессия передать не может:
- Порядок расширений сохраняется — он входит в JA3 и JA4.
- GREASE генерируется заново — значения создаются для каждого соединения; uTLS выдаёт свежие, в отпечатки они не входят.
pre_shared_key(0x0029) иearly_data(0x002a) отбрасываются — свежая сессия не может возобновить захваченные PSK.- Key shares синтезируются из захваченных supported groups: гибридные постквантовые клиенты (
X25519MLKEM768/X25519Kyber768) предлагают гибридный share плюс X25519; остальные — один share для предпочитаемой классической группы. - Наборы шифров, supported groups, форматы EC-точек, алгоритмы подписи,
supported_versionsи ALPN восстанавливаются из захвата;compress_certificateповторяется с brotli (предложение семейства Chrome); неизвестные расширения повторяются только по факту присутствия.
JA3 — это MD5 от строки legacyVersion,ciphers,extensions,groups,ecPointFormats с отфильтрованным GREASE; JA4 — форма FoxIO a_b_c.
Если по ALPN согласован h2 (и Force HTTP/1.1 выключен), транспорт uTLS сам пишет HTTP/2-префейс вместо фиксированного h2-стека Go: захваченный клиентский SETTINGS-фрейм — идентификаторы, значения и порядок — дословно, плюс захваченный порядок псевдозаголовков (HTTP/2-отпечаток в стиле Akamai).
Предпросмотр отпечатка перед отправкой
Диалог replay запрашивает отчёт «захват против replay» (POST /api/replay/fingerprint-report), который вообще не обращается к сети. Он показывает колонки Captured и Replay will send — JA3, JA4, ALPN, версию TLS, версию HTTP, User-Agent, порядок заголовков, h2 SETTINGS — и расхождения:
| Измерение | Важность | Когда отмечается |
|---|---|---|
ja4 | high | JA4 различается — антиботы (Cloudflare, Akamai, DataDome) сравнивают его в первую очередь |
ja3 | warning | JA3 различается — его всё ещё проверяют старые наборы правил WAF |
alpn / httpVersion / userAgent | warning | Списки ALPN различаются; h2-захват будет отправлен как HTTP/1.1; User-Agent противоречит ClientHello |
headerOrder / h2Settings | warning | Порядок расходится (нативный транспорт сортирует заголовки); нативный транспорт не может воспроизвести захваченный SETTINGS-фрейм |
tlsSession / headerSet / egress | info | PSK отброшен, набор заголовков отличается, отмечен выход через прокси |
Загрузка mTLS-клиентских сертификатов
Откройте Settings → mTLS client certificates. Сертификаты хранятся в локальной базе SQLite; ответы API никогда не возвращают PEM.
- Введите Name и Pinned hosts (через запятую, например
api-m.goldapple.ru). - Укажите один из двух форматов:
- Объединённый PEM — цепочка сертификатов, за которой следует приватный ключ (блок
PRIVATE KEY,RSA PRIVATE KEYилиEC PRIVATE KEY). Загрузки без приватного ключа отклоняются. - …или файл
.p12/.pfxс паролем — кодируется в base64 в браузере, разблокируется на стороне сервера и перекодируется в PEM.
- Объединённый PEM — цепочка сертификатов, за которой следует приватный ключ (блок
- Нажмите Store certificate. Если заданы оба варианта, приоритет у PEM. Лимит загрузки — 1 МиБ.
Привязка к хосту сопоставляется с именем целевого хоста replay: точное совпадение важнее совпадения по суффиксу, а среди суффиксных совпадений побеждает самое длинное (наиболее специфичное).
Подключение сертификата при replay
В диалоге replay установите Client certificate (mTLS) в Auto (host-pinned) (по умолчанию — бэкенд подключает сертификат, привязанный к целевому хосту, если он есть) или выберите конкретный сертификат по имени. Оба транспорта предъявляют сертификат, когда сервер присылает TLS CertificateRequest; ответ replay возвращает фактически использованный clientCertId.
[!TIP] Массовый replay ограничен 50 запросами на пакет.
Классы отказов
Каждый результат replay классифицируется, давая мутационным пробам, канареечным проверкам и массовым запускам стабильный словарь вердиктов:
| Класс | Значение |
|---|---|
| (пусто) — принят | 2xx; это не отказ |
transport-error | Сбой подключения или TLS-рукопожатия — HTTP-статуса нет |
client-certificate-required | HTTP 400, тело которого совпадает с mTLS-заглушкой nginx («No required SSL certificate…») |
unauthorized / forbidden / not-found | 401 / 403 / 404 |
rate-limited | 429 |
antifraud-reject | 451 — антифрод-слой отклонил запрос целиком |
redirect | 3xx — replay никогда не следует редиректам |
client-error / server-error | любой другой 4xx / 5xx |
client-certificate-required определяется сниффингом первых 4096 байт тела ответа 400 — это отличает заглушку отсутствующего mTLS-сертификата от обычного некорректного запроса. Диагноз ставится по паре: если подключение сертификата переворачивает client-certificate-required в 2xx или antifraud-reject, mTLS-барьер пройден, а следующий барьер — на прикладном уровне. Канареечные проверки оповещают о дрейфе класса отказа.
[!NOTE] Replay не следует редиректам, по умолчанию использует таймаут 30 с и исключает захваченные учётные данные, пока вы явно не включите их — см. /docs/ru/security/. Захваченные JA3/JA4 берутся из вкладки TLS-анализа (/docs/ru/analysis/comparing/).