24 KiB
JA3 и JA4 анализ в Telemt
Этот документ описывает, как использовать JA3/JA4 telemetry в Telemt для диагностики блокировок, которые происходят на основе TLS ClientHello, особенно JA4 TLS client fingerprint.
Цель документа практическая: помочь оператору понять, какой клиентский TLS-отпечаток реально доходит до Telemt, как он распределён по IP/CIDR/пользователям, и как отделить JA4-based фильтрацию от блокировки по IP, SNI, домену, server flight или активному сканированию.
Коротко
JA3 и JA4 описывают форму TLS ClientHello. ClientHello отправляет клиент, поэтому JA3/JA4 в этом контексте являются fingerprint'ами клиентской TLS-реализации, а не Telemt как сервера.
Telemt собирает JA3/JA4 только из уже прочитанного полного ClientHello:
- без packet capture;
- без MITM;
- без расшифровки TLS;
- без дополнительных сетевых чтений;
- без Prometheus labels с высокой кардинальностью;
- с ограниченным in-memory TTL/cap collector.
Собранные данные доступны:
- через API:
GET /v1/runtime/tls-fingerprints; - через
/beobachten, еслиgeneral.beobachten=true.
Основная польза:
- увидеть, какие JA4 реально используют клиенты;
- понять, один ли fingerprint страдает у всех пользователей;
- отделить проблему клиента от проблемы IP/ASN/домена;
- увидеть, доходят ли проблемные соединения до Telemt вообще;
- сравнить successful TLS-auth и bad/probe поток для одного fingerprint;
- собрать evidence для последующего изменения клиента, маршрута или deployment-профиля.
Что такое JA3
JA3 - старый и широко совместимый способ получить hash от TLS ClientHello.
JA3 строится из ClientHello fields:
SSLVersion,Cipher,SSLExtension,EllipticCurve,EllipticCurvePointFormat
Значения внутри полей записываются в порядке, в котором они пришли в ClientHello. GREASE values исключаются. Итоговая строка хэшируется MD5, поэтому в API есть два поля:
ja3- MD5 hash;ja3_raw- исходная строка, из которой получен hash.
Практическое значение JA3 в 2026 году ограничено тем, что современные TLS-клиенты и браузерные стеки могут менять порядок extensions. Поэтому JA3 полезен как совместимый исторический сигнал, но для диагностики современных блокировок обычно важнее JA4.
Что такое JA4
JA4 TLS client fingerprint - более структурированный fingerprint ClientHello.
JA4 в Telemt считается для TLS-over-TCP ClientHello и имеет форму:
t<version><sni_marker><cipher_count><extension_count><alpn_marker>_<cipher_hash>_<extension_hash>
Пример:
t13d1516h2_8daaf6152771_e5627efa2ab1
Части JA4:
| Часть | Смысл |
|---|---|
t |
TLS over TCP. Telemt сейчас не считает JA4 для QUIC/DTLS. |
13, 12, 11, 10 |
TLS version, предпочтительно из supported_versions. |
d / i |
Есть SNI domain (d) или SNI отсутствует (i). |
15 |
Количество cipher suites без GREASE, capped до 99. |
16 |
Количество extensions без GREASE, capped до 99. |
h2, h1, 00 |
ALPN marker: первый и последний символ первого ALPN value или 00. |
cipher_hash |
SHA256 от отсортированного списка ciphers, первые 12 hex chars. |
extension_hash |
SHA256 от отсортированных extensions плюс signature algorithms, первые 12 hex chars. |
Важное отличие JA4 от JA3: JA4 нормализует часть полей, поэтому он устойчивее к простому изменению порядка extensions. Это делает JA4 удобным для фильтров и одновременно полезным для диагностики таких фильтров.
Где Telemt видит ClientHello
В TLS/FakeTLS режиме Telemt получает первые bytes соединения и определяет, похоже ли оно на TLS handshake. Если record является полным ClientHello и проходит bounds checks, Telemt один раз парсит его для JA3/JA4.
Дальше возможны три исхода:
-
Успешный MTProxy/FakeTLS клиент
- Telemt принимает TLS-auth;
- fingerprint записывается в global/IP/CIDR scopes;
- после успешной TLS-auth Telemt добавляет user scope.
-
Bad client или probe
- ClientHello полный, но auth не проходит;
- fingerprint записывается в global/IP/CIDR scopes;
- user scope не записывается;
bad_or_probeувеличивается.
-
Неполный или обрезанный ClientHello
- fingerprint не считается;
- такие случаи остаются в существующих bad-class counters.
Если фильтр режет трафик до того, как TCP connection или ClientHello дошли до процесса Telemt, Telemt не увидит этот fingerprint. Это важнейшее диагностическое отличие: отсутствие fingerprint'а во время жалобы пользователя часто означает блокировку до приложения, а не проблему внутри Telemt.
Включение сбора
Collector включается, когда включён хотя бы один потребитель:
[general]
beobachten = true
beobachten_minutes = 10
или:
[server.api]
runtime_edge_enabled = true
runtime_edge_top_n = 50
Практически:
- для файлового/metrics endpoint анализа достаточно
general.beobachten=true; - для API snapshot нужен
server.api.runtime_edge_enabled=true; general.beobachten_minutesзадаёт retention window для fingerprint buckets;server.api.runtime_edge_top_nзадаёт default Top-N размер API snapshot.
API snapshot
Endpoint:
curl -s http://127.0.0.1:9091/v1/runtime/tls-fingerprints
С явным лимитом:
curl -s 'http://127.0.0.1:9091/v1/runtime/tls-fingerprints?limit=100'
Если API защищён header'ом:
curl -s \
-H 'Authorization: Bearer YOUR_TOKEN' \
'http://127.0.0.1:9091/v1/runtime/tls-fingerprints?limit=100'
Если runtime_edge_enabled=false, endpoint возвращает payload с:
{
"enabled": false,
"reason": "feature_disabled"
}
Структура payload
Основные поля:
| Поле | Смысл |
|---|---|
retention_secs |
Текущее TTL окно collector'а. |
capacity |
Максимум retained buckets. |
dropped_total |
Сколько новых buckets отброшено из-за cap. |
parse_error_total |
Сколько полных ClientHello не удалось распарсить. |
by_fingerprint |
Top fingerprints глобально. |
by_ip |
Top fingerprints по exact source IP. |
by_cidr |
Top fingerprints по source prefix: IPv4 /24, IPv6 /56. |
by_user |
Top fingerprints по authenticated user. |
Строка snapshot:
| Поле | Смысл |
|---|---|
scope |
IP, CIDR или username. В by_fingerprint отсутствует. |
ja3 |
JA3 hash. |
ja3_raw |
Raw JA3 string. |
ja4 |
JA4 TLS client fingerprint. |
ja4_raw |
Raw JA4 material. |
total |
Сколько полных ClientHello попало в этот bucket. |
auth_success |
Сколько из них успешно прошли TLS-auth. |
bad_or_probe |
Сколько были bad/probe после полного ClientHello. |
first_seen_epoch_secs |
Первый timestamp bucket'а. |
last_seen_epoch_secs |
Последний timestamp bucket'а. |
Быстрый просмотр через jq
Top JA4 глобально:
curl -s http://127.0.0.1:9091/v1/runtime/tls-fingerprints \
| jq -r '.data.data.by_fingerprint[] | [.ja4, .total, .auth_success, .bad_or_probe] | @tsv'
Top JA4 по пользователям:
curl -s http://127.0.0.1:9091/v1/runtime/tls-fingerprints?limit=100 \
| jq -r '.data.data.by_user[] | [.scope, .ja4, .total, .auth_success] | @tsv'
Top JA4 по CIDR:
curl -s http://127.0.0.1:9091/v1/runtime/tls-fingerprints?limit=100 \
| jq -r '.data.data.by_cidr[] | [.scope, .ja4, .total, .auth_success, .bad_or_probe] | @tsv'
Ошибки парсинга и drops:
curl -s http://127.0.0.1:9091/v1/runtime/tls-fingerprints \
| jq '.data.data | {retention_secs, capacity, dropped_total, parse_error_total}'
Beobachten output
Если включён endpoint metrics, /beobachten содержит обычные forensic buckets и, когда есть данные, append-only секцию TLS fingerprints:
curl -s http://127.0.0.1:9090/beobachten
Фрагмент:
[tls_fingerprints]
retention_secs=600 capacity=65536 dropped_total=0 parse_error_total=0
[tls_fingerprints.by_fingerprint]
ja4=t13d1516h2_8daaf6152771_e5627efa2ab1 ja3=... total=42 auth_success=41 bad_or_probe=1 first_seen=... last_seen=...
[tls_fingerprints.by_cidr]
scope=203.0.113.0/24 ja4=t13d1516h2_8daaf6152771_e5627efa2ab1 ja3=... total=10 auth_success=10 bad_or_probe=0 first_seen=... last_seen=...
/beobachten удобен для быстрой операторской диагностики без API client. API удобнее для автоматической корреляции.
Как анализировать JA4-based блокировку
1. Зафиксировать симптом
Перед анализом нужно записать:
- какие пользователи жалуются;
- какая версия Telegram client используется;
- какая платформа: Desktop, Android, iOS;
- какой источник сети: mobile ISP, home ISP, corporate network, country/region;
- работает ли тот же пользователь через другой network path;
- работает ли другой пользователь с того же IP/CIDR;
- видит ли Telemt новые ClientHello от проблемного пользователя в момент попытки.
JA4 без контекста почти всегда недостаточен. Фильтры часто используют сочетание:
- JA4;
- destination IP;
- SNI;
- порт;
- ASN/source network;
- rate или connection pattern;
- reputation домена/IP;
- active probing result.
2. Проверить, доходит ли ClientHello до Telemt
Во время попытки подключения проблемного пользователя смотрите:
curl -s 'http://127.0.0.1:9091/v1/runtime/tls-fingerprints?limit=200' \
| jq '.data.data.by_user, .data.data.by_ip, .data.data.by_cidr'
Интерпретация:
| Наблюдение | Вероятный вывод |
|---|---|
| Нет новых rows для IP/CIDR пользователя | Блокировка до Telemt: routing, firewall, ISP/DPI drop, IP block, SYN/TCP reset, UDP/TCP path issue. |
Есть by_ip/by_cidr, но нет by_user |
ClientHello дошёл, но TLS-auth/MTProxy layer не дошёл до успешного пользователя. Возможны bad key, probe, wrong client, active scanner, обрыв после ClientHello. |
Есть by_user.auth_success |
Клиентский JA4 дошёл и был принят Telemt. Если пользователь всё равно видит проблему, искать нужно дальше: relay path, Telegram upstream, quota, route mode, session cancellation, ME/direct routing. |
Резко растёт bad_or_probe для одного JA4 |
Вероятны сканеры или неправильные клиенты с тем же fingerprint family. |
3. Сравнить working и blocked случаи
Снимите snapshot во время working case и blocked case:
curl -s 'http://127.0.0.1:9091/v1/runtime/tls-fingerprints?limit=500' > tls-fp-working.json
curl -s 'http://127.0.0.1:9091/v1/runtime/tls-fingerprints?limit=500' > tls-fp-blocked.json
Сравните:
- появился ли тот же
ja4в blocked сети; - меняется ли
ja4между версиями клиента; - меняется ли только IP/CIDR при том же
ja4; - есть ли
auth_successдля того жеja4из других сетей; - отличается ли
bad_or_probeмежду сетями.
Ключевая матрица:
| Working JA4 | Blocked JA4 | Вывод |
|---|---|---|
| Same | Same, но blocked network не доходит до Telemt | Вероятна фильтрация по JA4 + destination/IP/SNI/network до приложения. |
| Same | Same, доходит и auth_success>0 |
JA4 ClientHello не является точкой отказа; искать post-auth проблему. |
| Different | Blocked только один JA4 | Вероятен client-version/platform-specific fingerprint block. |
| Same | bad_or_probe растёт, auth_success=0 |
Возможно, доходит не тот клиент/secret или фильтр/прокси ломает поток после ClientHello. |
4. Разделить client JA4 и server fingerprint
JA4 ClientHello - это клиентская сторона. Настройки Telemt вроде TLS-front server flight, mask_host, ticket-tail или CCS replay не меняют ClientHello, который отправляет Telegram client.
Если фильтр принимает решение строго после ClientHello, то серверные улучшения могут не помочь. В этом случае полезные действия:
- проверить обновление Telegram client;
- сравнить платформы и версии клиента;
- проверить, меняется ли JA4 на другой версии;
- проверить, блокируется ли тот же JA4 к другому destination;
- проверить, блокируется ли другой JA4 к тому же Telemt IP/SNI;
- собрать evidence для client-side fingerprint fix.
Если ClientHello проходит, а блокировка возникает после server response, тогда уже важны:
- форма FakeTLS server flight;
- TLS front profile fidelity;
mask_hostповедение для non-auth clients;- certificate/provenance fallback для сканеров;
- TCP relay behavior;
- upstream route к Telegram.
5. Коррелировать с packet capture
Telemt collector показывает только то, что процесс увидел. Для подтверждения фильтрации до Telemt нужен внешний capture.
На сервере:
sudo tcpdump -i any -w telemt-clienthello.pcap host CLIENT_IP and port 443
Быстрый tshark вывод ClientHello fields:
tshark -r telemt-clienthello.pcap -Y "tls.handshake.type == 1" -T fields \
-e frame.time_epoch \
-e ip.src \
-e ip.dst \
-e tcp.srcport \
-e tcp.dstport \
-e tls.handshake.extensions_server_name \
-e tls.handshake.extensions_alpn_str
Если на клиентской стороне capture видит ClientHello, а серверный capture не видит, проблема в сети между клиентом и сервером. Если серверный capture видит ClientHello, но Telemt API не видит fingerprint, проверьте порт, listener, PROXY protocol, TLS record fragmentation и bounds/errors.
Практические сценарии
Сценарий A: один JA4 перестал работать у многих пользователей
Признаки:
- один
ja4доминирует в жалобах; - у разных source CIDR нет
auth_success; - working пользователи используют другой JA4;
- обновление клиента меняет поведение.
Вероятный вывод: фильтр на стороне сети научился распознавать конкретный ClientHello family.
Действия:
- сравнить Telegram client versions;
- проверить, не используют ли пользователи старые клиенты;
- собрать
ja4,ja4_raw, platform/version, source network; - проверить тот же client через другую сеть;
- проверить другой client version через ту же сеть.
Сценарий B: один CIDR не работает, JA4 обычный
Признаки:
- тот же
ja4успешно работает из других сетей; - проблемный
/24или/56не доходит до Telemt или не получаетauth_success; - нет общей корреляции по версии клиента.
Вероятный вывод: проблема не в JA4 alone, а в source network policy или destination reputation.
Действия:
- сменить route/VPS/IP;
- проверить port;
- проверить SNI/domain reputation;
- сравнить с другим Telemt endpoint;
- смотреть server-side packet capture.
Сценарий C: много bad_or_probe на одном JA4
Признаки:
bad_or_probeвысокий;by_userпустой или слабый;- source IP/CIDR разнообразные;
- попытки не соответствуют реальным пользователям.
Вероятный вывод: активное сканирование или нерелевантный TLS traffic с похожим ClientHello.
Действия:
- смотреть
/beobachtenпо IP classes; - проверить
unknown_tls_sniи bad-client counters; - убедиться, что fallback
mask_hostотвечает правдоподобно; - не делать вывод о блокировке пользователей только по global
bad_or_probe.
Сценарий D: auth_success есть, но пользователь жалуется
Признаки:
- fingerprint присутствует в
by_user; auth_successрастёт;- соединение проходит TLS-auth.
Вероятный вывод: JA4 ClientHello не является причиной отказа в этом случае.
Действия:
- проверить user enabled/disabled status;
- проверить quota;
- проверить direct/ME route;
- проверить upstream health;
- проверить runtime events;
- смотреть relay/session logs.
Что нельзя вывести из JA3/JA4
JA3/JA4 не говорят:
- почему сеть приняла решение о блокировке;
- какой именно vendor DPI используется;
- был ли block только по JA4 или по связке JA4+IP+SNI;
- что произошло с соединением после TLS-auth;
- как выглядит server-side TLS fingerprint;
- как ведёт себя HTTP layer после TLS.
JA3/JA4 также не являются уникальной идентичностью человека. Это fingerprint клиентской TLS-реализации и её настроек. Один fingerprint может быть у большого числа пользователей.
Ограничения collector'а Telemt
- Считается только TLS ClientHello, который полностью дошёл до Telemt.
- QUIC/DTLS/HTTP JA4 variants не собираются.
- Truncated ClientHello не fingerprint'ится.
- User scope появляется только после успешной TLS-auth.
by_ipиby_cidrотражают source address после нормализации/PROXY protocol path, если он используется.- Collector bounded: при большом количестве уникальных buckets возможен рост
dropped_total. - Retention зависит от
general.beobachten_minutes. - Данные runtime in-memory; это snapshot для диагностики, а не долговременное хранилище.
Рекомендованный workflow расследования
- Включить
runtime_edge_enabled=trueи разумныйruntime_edge_top_n, например100. - Зафиксировать baseline в период нормальной работы.
- Во время жалобы снять API snapshot и
/beobachten. - Сравнить
by_user,by_ip,by_cidr,by_fingerprint. - Проверить, появляется ли problematic source в Telemt вообще.
- Если не появляется, снять packet capture на сервере и клиенте.
- Если появляется без
auth_success, проверить secret/client/proxy link и bad/probe counters. - Если появляется с
auth_success, исключить JA4 ClientHello как primary cause и перейти к relay/upstream/runtime диагностике. - Если один JA4 стабильно коррелирует с block, собрать client version/platform evidence.
- Проверить, меняет ли обновление клиента JA4 и результат подключения.
Минимальный incident report
Для полезного отчёта по JA4-based блокировке соберите:
time_window:
telemt_version:
server_ip:
server_port:
tls_domain:
mask_host:
client_platform:
client_version:
source_network:
source_ip_or_cidr:
ja4:
ja4_raw:
ja3:
total:
auth_success:
bad_or_probe:
seen_in_by_user: yes/no
seen_in_by_ip: yes/no
seen_in_by_cidr: yes/no
server_tcpdump_seen_clienthello: yes/no
client_tcpdump_sent_clienthello: yes/no
works_from_other_network: yes/no
works_with_other_client_version: yes/no
Этот набор обычно достаточен, чтобы отличить client fingerprint block от IP/SNI/reputation block и от post-auth проблем Telemt.
Источники форматов
- JA3 reference: https://github.com/salesforce/ja3
- JA4 technical details: https://github.com/FoxIO-LLC/ja4/blob/main/technical_details/JA4.md