JA4 parmak izi, TLS ClientHello mesajından hesaplanan üç parçalı bir dizedir: a_b_c. a kısmı okunabilir meta veridir (protokol, TLS sürümü, SNI, cipher ve extension sayıları, ALPN), b kısmı sıralanmış cipher listesinin 12 karakterlik SHA-256 özeti, c kısmı ise sıralanmış extension'lar ile imza algoritmalarının 12 karakterlik SHA-256 özetidir. b0da82dd1658 değerini aradıysanız: bu bir c bölümü ve Chromium'a ait. Daha açık söylemek gerekirse, Chromium tabanlı bir istemcinin eski ALPS extension kodunu kullanmaya devam ederken bir TLS 1.3 oturumunu sürdürdüğünde ürettiği değer bu. Sayfanın geri kalanında bunu nereden bildiğimizi ve herhangi bir JA4 dizesini kendiniz nasıl çözebileceğinizi gösteriyoruz.
JA4 parmak izi nasıl oluşturulur: a_b_c biçimi
FoxIO'nun resmi JA4 teknik spesifikasyonu, parmak izini alt çizgilerle birleştirilmiş, insan tarafından okunabilir bir önek ve iki kısaltılmış hash olarak tanımlar. GREASE değerleri her yerde yok sayılır ve tüm hash'ler küçük harflidir.
| Bölüm | Karakter | Neyi kodlar | Olası değerler |
|---|---|---|---|
| a | 1 | Taşıma katmanı | t = TCP üzerinden TLS, q = QUIC, d = DTLS |
| a | 2 | En yüksek TLS sürümü (varsa supported_versions değerinden, yoksa ClientHello sürümünden) | 13, 12, 11, 10, s3, d2, 00 = bilinmiyor… |
| a | 1 | SNI var mı? | d = alan adı (SNI gönderildi), i = SNI yok (genellikle doğrudan IP'ye bağlanılıyor) |
| a | 2 | Cipher suite sayısı (GREASE hariç) | 00–99 |
| a | 2 | Extension sayısı (GREASE hariç, SNI ve ALPN dahil) | 00–99 |
| a | 2 | İlk ALPN değerinin ilk ve son karakteri | h2, h1 (http/1.1), h3, 00 = ALPN yok |
| b | 12 | 4 karakterlik hex olarak yazılmış, sıralanmış ve virgülle birleştirilmiş cipher suite'lerin SHA-256 özeti | hiç yoksa 000000000000 |
| c | 12 | Extension'ların (sıralı, SNI 0000 ve ALPN 0010 çıkarılmış) + _ + gönderim sırasındaki imza algoritmalarının SHA-256 özeti | hiç yoksa 000000000000 |
İki ayrıntı sık sık kafa karıştırıyor. Birincisi, a kısmındaki extension sayısı SNI ve ALPN'yi içerir, ama c kısmındaki extension hash'i bunları dışarıda bırakır; dolayısıyla aynı istemci ister bir alan adına ister bir IP'ye bağlansın aynı c değerini üretir. İkincisi, imza algoritmaları sıralanmadan, istemcinin gönderdiği sırayla hash'lenir; yani imza tercihlerinin sırasını değiştiren bir istemci, extension'ları birebir aynı olsa bile c değerini değiştirir.
t13d1516h2_8daaf6152771_… dizesini parça parça çözmek
t: QUIC değil, TCP üzerinden TLS.13: istemci en yüksek sürüm olarak TLS 1.3 sunuyor.d: SNI extension'ı vardı, yani istemci bir alan adına bağlanıyordu.15: GREASE çıkarıldıktan sonra 15 cipher suite.16: GREASE çıkarıldıktan sonra, SNI ve ALPN sayılarak 16 extension.h2: ilk ALPN değerih2, yani istemci HTTP/2'yi tercih ediyor.8daaf6152771: aşağıdaki sıralı cipher dizesinin hash'i; herhangi bir SHA-256 aracıyla yeniden üretebilirsiniz:
printf '%s' "002f,0035,009c,009d,1301,1302,1303,c013,c014,c02b,c02c,c02f,c030,cca8,cca9" \
| sha256sum | cut -c1-12
# 8daaf6152771
Bu liste, üç TLS 1.3 suite'i ile Chrome'un on iki eski TLS 1.2 suite'inden oluşuyor. FoxIO örneklerinden headless Chrome 148'e kadar kontrol ettiğimiz her Chromium derlemesi hâlâ 8daaf6152771 üretiyor. Yani b bölümü size "Chromium ailesinden bir TLS yığını" der, sürüm hakkında ise neredeyse hiçbir şey söylemez. Sürüm farkları c bölümünde ortaya çıkar.
Spesifikasyonu dikkatle okuyorsanız küçük bir not: algoritma özetinde t13d1516h2_8daaf6152771_b186095e22b6 gösteriliyor, ama aynı belgedeki örnek hesaplama e5627efa2ab1 sonucunu veriyor. Örneği yeniden hesapladık ve e5627efa2ab1 bulduk; ilk dizeyi temsili bir örnek olarak görün.
b0da82dd1658 ne anlama geliyor?
b0da82dd1658, bir Chromium JA4'ünün c bölümüdür. Şu dizenin birebir hash'idir:
0005,000a,000b,000d,0012,0017,001b,0023,0029,002b,002d,0033,4469,fe0d,ff01_0403,0804,0401,0503,0805,0501,0806,0601
Bunu kendiniz doğrulayabilirsiniz:
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
Listedeki üç extension istemciyi tanımlıyor:
0029(pre_shared_key). Bu, TLS 1.3 oturum sürdürmedir (session resumption). Yalnızca istemcinin aynı sunucuya daha önce yaptığı bir bağlantıdan kalma bir ticket'ı varsa görünür. RFC 8446 §4.2.11 tarafından tanımlanır. Bu extension olmadan aynı tarayıcı02713d6af862değerini üretir.4469(ALPS, orijinal kod). Application-Layer Protocol Settings bir Chrome extension'ıdır. BoringSSL, Eylül 2023'te bunun için yeni bir kod ekledi (0x44cd) ve güncel Chrome yenisini gönderiyor. Dolayısıyla4469, eski bir Chromium derlemesine ya da böyle bir derlemeyi taklit eden bir araca işaret eder.fe0d(Encrypted Client Hello). Chrome sıradan bağlantılarda bir GREASE ECH extension'ı gönderir.
FoxIO'nun kendi ja4plus-mapping.csv dosyası, t13d1517h2_8daaf6152771_b0da82dd1658 ve t13i1516h2_8daaf6152771_b0da82dd1658 değerlerini "Chromium Browser" olarak etiketliyor. Önekteki aritmetik de tutuyor: hash'lenen 15 extension'a SNI ve ALPN eklenince SNI ile (d) 17, SNI olmadan (i) 16 çıkıyor. Bu, internette sıkça tekrarlanan bir tutarsızlığı da ortaya koyuyor. t13d1516h2_8daaf6152771_b0da82dd1658 gibi bir dize tek bir gerçek ClientHello'dan gelemez: SNI ve ALPN birlikte varken bu 15 hash'lenmiş extension'ın 17 sayısını vermesi gerekir.
Değeri doğrudan da yeniden ürettik. 2026-10-03 tarihinde impersonate="chrome131" ile çalışan curl_cffi 0.16.3, tls.peet.ws adresine ilk isteğini t13d1516h2_8daaf6152771_02713d6af862 olarak gönderdi. Aynı oturumdaki, TLS oturumunu sürdüren ikinci isteği ise t13d1517h2_8daaf6152771_b0da82dd1658 olarak döndü. Kısacası b0da82dd1658 "Chromium tarzı bir ClientHello, eski ALPS kodu, sürdürülen oturum" demektir. Bu tanıma gerçek eski Chrome, Edge, Brave ve Opera derlemeleri, gömülü Chromium ve geçiş öncesi bir Chrome profiline sabitlenmiş taklit kütüphaneleri girer. Tek başına bir JA4 bunları birbirinden ayıramaz.
Referans tablosu: istemcilere göre gerçek JA4 değerleri
Aşağıdaki değerler yalnızca iki kaynaktan geliyor: FoxIO'nun yayımladığı örnekler ve eşleme dosyası ile 2026-10-03'te tls.peet.ws'e karşı yaptığımız kendi kayıtlarımız (sürümler belirtilmiştir). Kütüphane değerleri büyük ölçüde TLS arka ucuna ve derleme seçeneklerine bağlıdır; kütüphane satırlarını evrensel sabitler olarak değil, örnek olarak görün. Doğrulayamadığımız satırları, kendi gerçek Firefox ve Safari kayıtlarımız dahil, tabloya almadık.
| İstemci | JA4 | Kaynak |
|---|---|---|
| Headless Chrome 148 (Linux), yeni bağlantı | t13d1516h2_8daaf6152771_d8a2da3f94cd | Kendi kaydımız, Playwright Chromium |
| Aynı tarayıcı, sürdürülen oturum | t13d1517h2_8daaf6152771_b6f405a00624 | Kendi kaydımız |
| Chromium, eski ALPS kodu, yeni / sürdürülen | t13d1516h2_8daaf6152771_02713d6af862 / t13d1517h2_8daaf6152771_b0da82dd1658 | FoxIO eşleme CSV'si; curl_cffi chrome131 ile yeniden üretildi |
| QUIC üzerinden Chrome | q13d0312h3_55b375c5d22e_178839b6cec1 | FoxIO README |
| Mozilla Firefox (sürüm belirtilmemiş) | t13d1715h2_5b57614c22b0_7121afd63204 | FoxIO eşleme CSV'si |
| Safari (sürüm belirtilmemiş) | t13d2014h2_a09f3c656075_14788d8d241b | FoxIO eşleme CSV'si |
| curl 8.5.0 / OpenSSL 3.0.13 (Ubuntu) | t13d3112h2_e8f1e7e78f70_b26ce05bbdd6 | Kendi kaydımız; tls.peet.ws, BrowserLeaks ve Scrapfly'da aynı |
| Python requests 2.31 / urllib3 2.0.7, OpenSSL 3.0.13 | t13d3112h1_e8f1e7e78f70_b26ce05bbdd6 | Kendi kaydımız |
| Go 1.24.1 net/http (varsayılan istemci) | t13d1311h2_f57a46bbacb6_e7c285222651 | Kendi kaydımız |
curl_cffi 0.16.3, impersonate="chrome146" | t13d1516h2_8daaf6152771_d8a2da3f94cd | Kendi kaydımız |
curl_cffi 0.16.3, impersonate="firefox147" | t13d1717h2_5b57614c22b0_3cbfd9057e0d | Kendi kaydımız |
curl_cffi 0.16.3, impersonate="safari2601" | t13d2013h2_a09f3c656075_7f0f34a4126d | Kendi kaydımız |
Tek tek satırlardan çok örüntüler önemli:
- c bölümü çoğu zaman uygulamanın değil, TLS kütüphanesinin parmak izidir. Aynı OpenSSL 3 derlemesindeki curl ve Python
b26ce05bbdd6değerini paylaşıyor. FoxIO'nun eşleme dosyasında öneki farklı ama c değeri aynı olan bir Python kaydı var. FoxIO dosyasındaki Go istemcileri, bizim Go 1.24 kaydımızlae7c285222651değerini paylaşıyor. - requests
h1gösteriyor. urllib3 2.x ALPN'de yalnızcahttp/1.1duyuruyor; bu yüzden a bölümü, tek bir başlık okunmadan sunucuya bir tarayıcıyla konuşmadığını söylüyor. - Düz bir kütüphane yalnızca sayılarından kolayca tanınır. 31 cipher (OpenSSL varsayılanı) ya da 13 cipher ile 11 extension (Go), güncel her Chromium derlemesinin gönderdiği 15/16 örüntüsüne hiç benzemez.
- Oturum sürdürme her tarayıcıda c değerini değiştirir. curl_cffi kayıtlarımızda sürdürülen oturumlarda Firefox 17'den 18 extension'a, Safari 13'ten 14'e çıkıyor. Yalnızca yeni bağlantı değerini izin listesine alan bir tespit kuralı, geri dönen gerçek ziyaretçilerde yanlış alarm verir.
Chrome satırının değişmeye devam etmesini bekleyin. curl_cffi'nin en yeni chrome150 profili üç imza algoritması ekliyor: 0904, 0905 ve 0906. Bunlar IETF taslağındaki ML-DSA kodları ve c değerini 806a8c22fdea yapıyorlar. Bunu kararlı bir Chrome 150 derlemesiyle doğrulayamadık; referans değer olarak değil, bir ön izleme olarak görün.
JA4 cipher'ları ve extension'ları neden sıralıyor?
JA4 cipher'ları ve extension'ları sıralıyor, çünkü Chrome extension sırasını kasıtlı olarak rastgele hale getiriyor ve sıraya duyarlı bir parmak izi (JA3) artık kararlı değil. Chrome, 2023 başında Chrome 110 civarında TLS ClientHello extension permütasyonunu yayımladı. Amaç, sunucuların ve ara cihazların sabit bir düzene bağımlı olmasını önlemekti. Fastly etkisini ölçtü: JA3 extension'ları gönderim sırasıyla hash'lediği için tek bir Chrome kurulumu neredeyse her bağlantıda farklı bir JA3 üretiyor.
JA4 bunu hash'lemeden önce sıralayarak çözüyor. FoxIO onu Eylül 2023'te JA4+ paketinin bir parçası olarak yayımladı (APNIC'teki yeniden yayın). Bugün Cloudflare Bot Management, AWS CloudFront ve WAF, Google Cloud Armor, Fastly, Akamai ve FoxIO README'sinde listelenen diğerleri tarafından sunuluyor.
Scraper'lar için bunun iki yüzü var. Extension sırasını rastgele yapmak artık parmak izinizi değiştirmiyor, yani o hile öldü. Hâlâ önemli olan, cipher kümesi, extension kümesi ve imza algoritmalarının sırası. Pratikte bu, gerçek bir tarayıcının kullandığı TLS yığınını ya da onu yakından taklit eden bir kütüphaneyi kullanmak demek. Orijinal sıralı görünüme ihtiyacınız varsa (örneğin JA3 ile karşılaştırmak için), spesifikasyon JA4_o ile ham varyantlar JA4_r / JA4_ro değerlerini tanımlıyor. BrowserLeaks dördünü de döndürüyor. JA3'ü daha ayrıntılı olarak TLS parmak izi rehberimizde anlatıyoruz.
JA4+ ailesi: JA4S, JA4H, JA4X, JA4T
JA4, daha büyük bir paketteki yöntemlerden yalnızca biri. Diğerleri sunucuya, HTTP katmanına, sertifikalara ve TCP'ye bakıyor ve farklı bir lisansa tabi.
| Yöntem | Parmak izi alınan | Kısaca biçim |
|---|---|---|
| JA4S | Sunucunun ServerHello mesajı | protokol + sürüm + extension sayısı + ALPN, ardından seçilen cipher, ardından sunucu extension'larının hash'i |
| JA4H | HTTP isteği | metot (ge, po…), sürüm (11, 20), çerez c/n, referer r/n, başlık sayısı, Accept-Language'ın ilk 4 karakteri; ardından sırasıyla başlık adlarının, sıralanmış çerez adlarının ve sıralanmış çerez ad=değer çiftlerinin hash'leri |
| JA4X | X.509 sertifikası | issuer RDN OID'lerinin, subject RDN OID'lerinin ve extension OID'lerinin hash'leri (sertifikanın değerleri değil, nasıl oluşturulduğu) |
| JA4T | TCP SYN | pencere boyutu, sıralı TCP seçenekleri, MSS, pencere ölçeği; örneğin Windows 11 için 64240_2-1-3-1-1-4_1460_8 |
Biçimler FoxIO'nun teknik ayrıntı diyagramlarından ve referans Python uygulamasından alınmıştır. Scraping açısından en önemlisi JA4H. b bölümü başlık adlarını gönderildikleri sırayla hash'lediği için Chrome'un başlıklarını yanlış sırada gönderen bir istemci, her değer doğru olsa bile görünür hale gelir. İlişkili SETTINGS ve pseudo-header sırası sinyallerini HTTP/2 parmak izi yazımızda ele alıyoruz. JA4T ise işletim sistemini açığa çıkarır: User-Agent ne derse desin, bir Linux sunucusunun SYN paketi Windows'a benzemez.
Lisanslama
Deponun lisans bölümüne göre JA4 (TLS istemci parmak izi), JA3 gibi BSD 3-Clause lisanslıdır ve FoxIO onun üzerinde hiçbir patent talebi olmadığını söylüyor. JA4S, JA4L, JA4LS, JA4H, JA4X, JA4SSH, JA4T, JA4TS, JA4TScan, JA4D, JA4D6 ve diğer "JA4+" yöntemleri ise patent başvurusu aşamasında ve FoxIO License 1.1 ile lisanslanıyor. Bu lisans kurum içi ve akademik kullanıma izin veriyor, ancak JA4+ parmak izini bir ürünün parçası olarak satan bir sağlayıcının OEM lisansına ihtiyacı var.
QUIC ve HTTP/3: q öneki size ne söyler?
q ile başlayan bir JA4, bir QUIC Initial paketinden hesaplanmıştır; yani istemci HTTP/3 bağlantısı kuruyordu. QUIC, CRYPTO çerçevelerinin içinde bir TLS 1.3 ClientHello taşır. Initial paketin koruma anahtarları, istemcinin seçtiği Destination Connection ID'den türetilir (RFC 9001 §5.2); dolayısıyla yol üzerindeki herhangi bir gözlemci veya edge sunucusu paketi çözebilir ve ClientHello'nun parmak izini TCP'de olduğu gibi birebir çıkarabilir.
Chrome'un QUIC parmak izi TCP'dekinden çok farklı görünür: FoxIO örneğinde q13d0312h3_55b375c5d22e_178839b6cec1. Bu, 3 cipher (QUIC eski sürümleri yasakladığı için yalnızca TLS 1.3) ve h3 ALPN değeri demek. Otomasyon açısından önemi şu: tarayıcılar bir site HTTP/3 duyurduğunda ona geçer, oysa çoğu HTTP istemcisi hiç geçmez. Cloudflare'in belgelenmiş JA4 Signals verileri arasında h2h3_ratio_1h adlı bir değer var: belirli bir JA4 için HTTP/2 ile HTTP/3 üzerinden gelen trafiğin oranı. HTTP/3 destekleyen bir sitede QUIC üzerinden hiç görünmeyen bir "Chrome" TLS parmak izi istatistiksel bir aykırı değerdir. curl_cffi README'si, HTTP/3 parmak izi taklidinin v0.15.0'dan beri desteklendiğini belirtiyor.
Kendi JA4 değerinizi nasıl görürsünüz?
En hızlı kontrol, ClientHello'nuzu okuyup parmak izini döndüren bir yankı servisi kullanmak. Aşağıdaki üç servis testlerimizde JA4 döndürdü ve birbirleriyle bayt bayt aynı sonucu verdi:
- tls.peet.ws/api/all:
tls.ja4,tls.ja4_r, JA3, HTTP/2 Akamai parmak izi vehttp_versioniçeren JSON. - tls.browserleaks.com/json:
ja4,ja4_r,ja4_o,ja4_roiçeren JSON. - Scrapfly'ın JA3/JA4 aracı;
tools.scrapfly.io/api/fp/ja3adresindeki API'sija4veja4_rdöndürüyor.
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'])"
Aynı kontrolü yalnızca dizüstü bilgisayarınızdan değil, proxy'niz üzerinden de yapın. CONNECT ile tünel kuran bir forward proxy ClientHello'nuzu olduğu gibi iletir, ama TLS'i araya girerek açan bir proxy, kurumsal bir ara cihaz ya da bazı SDK katmanları kendi ClientHello'larını koyar. Örneğin bir ProxyHat residential çıkışıyla:
curl -s -x http://USERNAME:PASSWORD@gate.proxyhat.com:8080 https://tls.peet.ws/api/all
Wireshark ve tshark
TLS alan referansına göre Wireshark, 4.2.0'dan beri JA4'ü yerel olarak tls.handshake.ja4 (ve tls.handshake.ja4_r) görüntüleme filtresi alanında hesaplıyor. FoxIO'nun JA4+ eklentisi (Wireshark 4.4.0 veya üstü) paketin geri kalanını ja4.* altında ekliyor; örneğin ja4.ja4s, ja4.ja4h ve ja4.ja4t. Bir kayıttan parmak izlerini çıkarmak için:
tshark -r capture.pcapng -Y "tls.handshake.ja4" -T fields \
-e ip.dst -e tls.handshake.extensions_server_name -e tls.handshake.ja4
Kaydı, istemciyi sizin kontrol ettiğiniz bir makinede alın. Headless bir tarayıcının HTTPS trafiğinin parmak izini çıkarmak için tarayıcıyı yerelde çalıştırın ve loopback ya da giden arayüzde kayıt alın. ClientHello şifresiz olduğundan JA4 için TLS anahtarlarına ihtiyacınız yok. HTTPS üzerinde JA4H için ise gerekiyor.
Pratikte anlamı: başlıklar el sıkışmayla uyuşmalı
User-Agent'ı değiştirmek JA4'ünüzü değiştirmez. Chrome User-Agent'ı gönderen bir Python betiği, tek bir başlık okunmadan el sıkışmada yine t13d3112h1_e8f1e7e78f70_b26ce05bbdd6 sunar. Bu uyuşmazlık (Chrome olduğunu iddia ediyor, OpenSSL gibi müzakere ediyor, HTTP/1.1 istiyor) bir edge'in yapabileceği en ucuz kontrollerden biri. JA4 veritabanları da tam olarak bunu yakalamak için kuruluyor.
Yaygın iki çözüm var. İkisinin de sınırları var.
- curl_cffi (curl-impersonate için Python bağlamaları), ClientHello ve HTTP/2 çerçevelerini belirtilen bir tarayıcı profiline uyacak şekilde oluşturur:
requests.get(url, impersonate="chrome"). Kayıtlarımızda güncel Chrome profilleri gerçek bir headless Chrome 148 ile aynı JA4'ü üretti. Oturumları ve proxy'leri curl_cffi rehberimizde anlatıyoruz. - Go için uTLS,
crypto/tlspaketinin ClientHello'sunutls.UClient(conn, &config, helloID)aracılığıylatls.HelloChrome_Autogibi bir "parrot" ile değiştirir. README'si, taklidin kusurlu olabileceğini ve ClientHello'nun ötesine geçmediğini açıkça belirtiyor. Go uTLS rehberimiz, bununet/httpile nasıl bağlayacağınızı gösteriyor.
Taklidin çözmedikleri
Eşleşen bir JA4 sizi yalnızca ilk filtreden geçirir.
- JA4, iddia edilen tarayıcı sürümüyle de uyuşmalı: geçiş öncesi ALPS kodlu (
b0da82dd1658) bir Chrome 148 User-Agent'ı, kendi başına küçük bir uyuşmazlıktır. - JA4H başlık sırası da uyuşmalı.
- JA4T ve IP verileri sunucunun işletim sistemini ve ağını ele verir.
- JavaScript doğrulamaları bir HTTP istemcisinde hiç çalışmaz.
- Davranış (istek hızı, gezinme örüntüsü) ayrıca değerlendirilir.
Gönderdiğiniz User-Agent'a uyan profili seçin, oturum sürdürme normal görünsün diye oturumları açık tutun ve çıkış IP'sini trafiğe uygun tutun. Residential bir çıkış, TLS katmanını değil, ağ itibarı katmanını düzeltir. Parmak izini yukarıda gösterildiği gibi proxy üzerinden kontrol edin.
Son olarak: parmak izlerini anlamanın amacı, otomatik erişimi reddetmeye karar vermiş bir siteyi aşmak değil, meşru otomasyonu dürüst ve öngörülebilir kılmaktır. Geçerli olduğu yerlerde robots.txt'ye ve kullanım koşullarına uyun; kişisel verileri kazımanın, kusursuz bir JA4'ün hiçbir şey yapamayacağı yasal yükümlülükler getirdiğini de unutmayın.






