iplogs.com

JA3 and JA4 Fingerprinting Explained: How TLS Reveals Your VPN Client

JA3 and JA4 hash the TLS ClientHello to reliably identify the client library. Why Chrome looks different from Firefox, and OpenVPN from both. Full breakdown.

·13 min readJA3JA4TLS fingerprintingVPN detection

JA3 and JA4 are two hash-based TLS ClientHello fingerprinting schemes that are used across the network-security industry: censorship systems use them for blocking, CDNs use them for bot detection, and VPN-detection services like IPLogs use them for classification. This post explains what they are, what they capture, how to compute them, and why they are surprisingly reliable for identifying VPN clients.

What JA3 captures

A TLS ClientHello contains a large amount of client-specific state:

  • TLS version (e.g. 0x0303 for TLS 1.2)
  • Cipher suites in a specific order
  • TLS extensions in a specific order
  • Named elliptic curves (supported groups)
  • Elliptic-curve point formats

JA3 concatenates those fields with hyphens and commas and takes the MD5 hash. The result is a 32-character hexadecimal fingerprint. Two TLS clients built from the same library and configuration produce the same JA3. Two clients from different libraries produce different JA3s — even when they negotiate the same connection.

JA3 is a one-way hash of the cipher suite order, extension order, and curve preferences. It is small, fast to compute, and difficult to forge without deeply modifying the TLS client.

Computing a JA3

The canonical JA3 string for Firefox 119 on macOS looks like:

771,4865-4867-4866-49195-49199-52393-52392-49196-49200,0-23-65281-10-11-35-16-5-34-51-43-13-45-28-21,29-23-24-25-256-257,0

Applying MD5 to that string yields the JA3 hash. Libraries implementing JA3 exist for Go (dreadl0ck/ja3), Rust (s0cks/rust-ja3), Python (salesforce/ja3), and Zeek. The dreadl0ck Go implementation is used internally by IPLogs and is about 29× faster than the Python reference.

What JA4 changes

JA4 was introduced in 2023 by FoxIO. It fixes three limitations of JA3:

  • MD5 replaced. JA4 uses the first 12 characters of a truncated hash, increasing readability and enabling partial matching.
  • Separate TCP and QUIC variants. JA4 includes a protocol prefix — t for TCP, qfor QUIC — so you can distinguish between a client's TLS-over-TCP and TLS-over-QUIC fingerprints without recomputing.
  • Sorted cipher suites.JA4 sorts the cipher-suite list before hashing, which means minor ordering differences don't produce different hashes. This helps against naive evasion.

Why VPN clients have distinctive fingerprints

Every major commercial VPN client uses one of a few underlying TLS libraries — and each library produces a narrow set of JA3/JA4 values. Examples observed in IPLogs production:

  • OpenVPN over TCP/443 with TLS-crypt emits a JA3 hash distinct from any browser — wrong cipher order, no ALPN, no server_name in ClientHello in some configurations.
  • WireGuard wrapped in stunnel emits the stunnel OpenSSL JA3 which is a known fingerprint across the industry.
  • REALITY-based proxies (Xray, sing-box) are designed to mimic a browser JA3 but do so imperfectly — SNI fuzzing reliably triggers their cert-switch behavior, which is itself a signal.

How IPLogs uses JA3/JA4

When a request reaches the IPLogs backend, the Go TLS stack extracts the raw ClientHello and computes both a JA3 and a JA4. The hashes are matched against a curated database of known-VPN fingerprints. A match raises the ja3_known_vpn signal at weight 0.7 — high enough on its own to push a verdict tovpn_likely when combined with even one other signal.

Limitations

JA3/JA4 is deterministic only for the library. The VPN operator who wantsto evade fingerprinting can replace their TLS library's ClientHello field order to mimic a popular browser. This is what modern anti-censorship proxies like Xray/REALITY and VMess WebSocket attempt to do. It works when done precisely; in practice most implementations leave subtle artifacts in extension order or in the server_name field that active probing can still detect.

Try it

Paste any IP into the home-page checker and — if the IP maintains a reachable HTTPS service — the engine will collect and classify its JA3/JA4 alongside the other six detection layers. See the API docs for the exact signal names.

References

  • Althouse, Atkinson, Atkins, "JA3 — A method for profiling SSL/TLS clients", Salesforce Engineering 2017.
  • FoxIO, "JA4 — Network fingerprinting standard", 2023.
  • dreadl0ck/ja3 (Go implementation used in IPLogs), github.com/dreadl0ck/ja3.

Check any IP against the 7-layer pipeline

The detection methods described above are all available through the IPLogs public API, free, no signup required.

Try the IP checker →