Fingerprinting TLS explicado: JA3, JA4 y cómo evitar la detección

Aprende cómo el fingerprinting TLS revela la identidad de tu scraper a través de hashes JA3/JA4, análisis de suites de cifrado y señales HTTP/2 — más estrategias de mitigación usando bibliotecas TLS de nivel navegador.

Fingerprinting TLS explicado: JA3, JA4 y cómo evitar la detección

What Is TLS Fingerprinting?

TLS fingerprinting is a passive detection technique that identifies clients based on how they initiate encrypted connections. Every time your scraper, browser, or HTTP library connects to a website over HTTPS, it sends a TLS ClientHello message containing cipher suites, extensions, elliptic curves, and other parameters in a specific order. Anti-bot systems analyze this handshake to determine whether the connecting client matches what its user-agent claims to be.

Unlike browser fingerprinting, which requires JavaScript execution, TLS fingerprinting works at the network layer — before any page content is delivered. This makes it one of the earliest and most difficult detection signals to evade, as covered in our comprehensive guide to how anti-bot systems detect proxies.

How TLS Handshakes Work

Before any HTTP data is exchanged over HTTPS, the client and server perform a TLS handshake. The critical first message — the ClientHello — contains everything anti-bot systems need for fingerprinting:

  1. TLS version: The maximum TLS version the client supports (e.g., TLS 1.2, TLS 1.3).
  2. Cipher suites: An ordered list of encryption algorithms the client is willing to use.
  3. Extensions: Additional capabilities such as Server Name Indication (SNI), ALPN, signature algorithms, and key share groups.
  4. Elliptic curves: Supported curve types for key exchange (e.g., x25519, secp256r1).
  5. Compression methods: Typically null in modern implementations, but their presence or absence is still a signal.

Each HTTP library, browser, and programming language runtime produces a distinct ClientHello pattern. Chrome, Firefox, Safari, Python's requests, Go's net/http, and Node.js each have recognizable signatures.

JA3 Fingerprinting

JA3 is the most widely deployed TLS fingerprinting method. Developed by Salesforce engineers, it creates an MD5 hash from five fields in the ClientHello message:

FieldDescriptionExample Values
TLS VersionThe protocol version offered771 (TLS 1.2), 772 (TLS 1.3)
Cipher SuitesOrdered list of cipher suite codes4865-4866-4867-49195-49199...
ExtensionsList of extension type codes0-23-65281-10-11-35-16-5...
Elliptic CurvesSupported named groups29-23-24
EC Point FormatsSupported point format types0

These five values are concatenated with commas and hashed to produce a 32-character JA3 fingerprint. For example, Python's requests library produces a different JA3 hash than Chrome, even when both set the same user-agent string.

JA3 Detection in Practice

# Example JA3 hash computation (conceptual)
# ClientHello fields → concatenated string → MD5 hash
# Python requests (urllib3/OpenSSL) — distinct JA3
# ja3: 771,4866-4867-4865-49196-49200-159-52393-52392-52394...,0-23-65281-10-11...
# ja3_hash: "773906b0efdefa24a7f2b8eb6985bf37"
# Chrome 120+ — different cipher order, different extensions
# ja3: 771,4865-4866-4867-49195-49199-49196-49200-52393-52392...,0-23-65281-10-11...
# ja3_hash: "cd08e31494f9531f560d64c695473da9"
# The hash reveals the client library, regardless of User-Agent

JA4 — The Next Generation

JA4, also from Salesforce, improves on JA3 by producing a more readable and robust fingerprint. Instead of an opaque MD5 hash, JA4 creates a structured identifier with three components:

  • JA4_a: Protocol type + TLS version + SNI presence + cipher count + extension count + ALPN first value (e.g., "t13d1517h2_8daaf6152771_b0da82dd1658").
  • JA4_b: Sorted truncated hash of cipher suites.
  • JA4_c: Sorted truncated hash of extensions (with SNI and ALPN removed to reduce variability).

JA4 is harder to spoof because it incorporates additional signals and uses a format that resists simple hash matching.

Common TLS Fingerprints by Client

ClientTLS LibraryRecognizable TraitsDetection Risk
Chrome (latest)BoringSSLSpecific cipher order, GREASE values, ECH supportLow (if matched correctly)
FirefoxNSSDifferent cipher preference, delegated credentials extensionLow (if matched correctly)
Python requestsOpenSSL (via urllib3)Missing GREASE, fewer extensions, OpenSSL cipher orderVery High
Go net/httpGo crypto/tlsUnique cipher order, missing many extensionsVery High
Node.js (axios/got)OpenSSL (via Node)Node-specific extension order, missing GREASEHigh
curlVaries (OpenSSL/NSS/etc.)Depends on build, but typically non-browser fingerprintHigh

Why TLS Fingerprinting Is Hard to Evade

TLS fingerprinting presents unique challenges compared to other detection methods:

  • Network-layer detection: It operates before any HTTP content is exchanged, so it cannot be defeated by JavaScript injection or header manipulation.
  • Library-level signature: The fingerprint is determined by the TLS library compiled into your runtime, not by your application code. Changing the user-agent string has zero effect on the TLS fingerprint.
  • Proxy transparency: Standard HTTP/HTTPS proxies (including residential proxies) forward the TLS handshake from the client to the server, so the origin sees your client's real TLS fingerprint.
  • Version coupling: Each minor version of a TLS library can produce a slightly different fingerprint, making version mismatches detectable.

TLS Fingerprinting Mitigation Strategies

1. Use Browser-Grade TLS Libraries

The most effective approach is to use TLS libraries that produce browser-identical ClientHello messages:

# Python: Use curl_cffi to mimic browser TLS fingerprints
# pip install curl_cffi
from curl_cffi import requests
# Impersonate Chrome's TLS fingerprint
response = requests.get(
    "https://example.com",
    impersonate="chrome",
    proxies={
        "http": "http://USERNAME:PASSWORD@gate.proxyhat.com:8080",
        "https": "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
    }
)
print(response.status_code)

2. Use utls in Go

// Go: Use uTLS to mimic browser TLS fingerprints
// go get github.com/refraction-networking/utls
package main
import (
    "fmt"
    "io"
    "net/http"
    "net/url"
    "crypto/tls"
    tls2 "github.com/refraction-networking/utls"
)
func main() {
    proxyURL, _ := url.Parse("http://USERNAME:PASSWORD@gate.proxyhat.com:8080")
    transport := &http.Transport{
        Proxy: http.ProxyURL(proxyURL),
        TLSClientConfig: &tls.Config{InsecureSkipVerify: false},
    }
    // uTLS allows you to specify a ClientHelloID that mimics
    // specific browsers (Chrome, Firefox, Safari, etc.)
    // This requires custom dial integration — see uTLS docs
    _ = tls2.HelloChrome_Auto // Example: mimic Chrome
    client := &http.Client{Transport: transport}
    resp, err := client.Get("https://example.com")
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
    body, _ := io.ReadAll(resp.Body)
    fmt.Println(string(body[:100]))
}

3. Use Node.js with Custom TLS

// Node.js: Use got-scraping for browser-like TLS
// npm install got-scraping
import { gotScraping } from 'got-scraping';
const response = await gotScraping({
    url: 'https://example.com',
    proxyUrl: 'http://USERNAME:PASSWORD@gate.proxyhat.com:8080',
    headerGeneratorOptions: {
        browsers: ['chrome'],
        operatingSystems: ['windows'],
    }
});
// got-scraping uses custom TLS settings to mimic browser fingerprints
console.log(response.statusCode);

4. Use Headless Browsers

Headless browsers (Puppeteer, Playwright) produce authentic browser TLS fingerprints because they use the real browser TLS stack. This is the most reliable mitigation but also the most resource-intensive. See our guide to scraping without getting blocked for setup details.

Testing Your TLS Fingerprint

Before deploying your scraper, verify its TLS fingerprint against detection services:

# Check your JA3 fingerprint against a test service
# Using Python with curl_cffi
from curl_cffi import requests
response = requests.get(
    "https://tls.peet.ws/api/all",
    impersonate="chrome",
    proxies={
        "http": "http://USERNAME:PASSWORD@gate.proxyhat.com:8080",
        "https": "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
    }
)
data = response.json()
print(f"JA3 Hash: {data.get('tls', {}).get('ja3_hash', 'N/A')}")
print(f"JA4: {data.get('tls', {}).get('ja4', 'N/A')}")
print(f"HTTP Version: {data.get('http_version', 'N/A')}")
Your TLS fingerprint is determined by your HTTP client library, not by your proxy. Switching from datacenter to residential proxies changes your IP reputation but does not change your TLS signature. Both layers must be addressed.

HTTP/2 Fingerprinting

Beyond TLS, the HTTP/2 protocol itself reveals client identity through connection settings, header frame order, and priority frames. Anti-bot systems combine TLS and HTTP/2 fingerprints for higher accuracy:

HTTP/2 SignalWhat It Reveals
SETTINGS frame valuesInitial window size, max concurrent streams — differs by client
WINDOW_UPDATE sizeFlow control increment value — unique to each implementation
Header frame orderPseudo-header ordering (:method, :authority, :scheme, :path)
PRIORITY framesStream dependency and weight — browser-specific patterns

Libraries like curl_cffi and got-scraping address HTTP/2 fingerprinting in addition to TLS fingerprinting.

Combining TLS Mitigation with Proxy Rotation

An effective anti-detection strategy layers TLS fingerprint matching with high-quality proxy rotation:

  1. Match TLS to user-agent: If your user-agent claims Chrome, your TLS fingerprint must match Chrome.
  2. Use residential proxies: ProxyHat's residential proxies provide clean IPs that complement browser-grade TLS signatures.
  3. Rotate consistently: Each session should use a matching IP + TLS profile + user-agent combination.
  4. Avoid mixing libraries: Do not reuse the same IP with different TLS fingerprints — this is a strong bot signal.
  5. Test before deployment: Verify your fingerprint matches your claimed browser using test endpoints.

For language-specific proxy integration, see our guides for Python, Node.js, and Go.

Ethical and Legal Considerations

TLS fingerprint mimicry should be used responsibly. Legitimate use cases include:

  • Accessing publicly available data through standard HTTPS connections
  • Security research and penetration testing of your own infrastructure
  • Ensuring your automated tests accurately simulate real browser behavior
  • Privacy research studying how TLS fingerprinting affects user tracking

Always respect website terms of service, rate limits, and applicable regulations. Refer to ProxyHat's documentation for responsible usage guidelines.

Preguntas frecuentes

¿Listo para empezar?

Accede a más de 50M de IPs residenciales en más de 148 países con filtrado impulsado por IA.

Ver preciosProxies residenciales
← Volver al Blog