unmask

docs

JA4 acquisition, LB / CDN setup, supported distros, FAQ.

A JA4 fingerprint is a client "fingerprint" extracted from the TLS handshake (ClientHello). It is unique to each attack tool and does not change even when the IP / country / VPN / User-Agent is switched.

However, whether JA4 can be captured depends on "who receives the TLS handshake first (where TLS is terminated)". This page lists the feasibility for each representative setup pattern.

Conclusion: it depends on where TLS is terminated

[Client] ──TLS handshake──▶ [ only whoever saw the ClientHello can compute JA4 ]

Computing JA4 requires the raw ClientHello byte sequence. A process that only sees the plaintext HTTP after TLS decryption cannot reconstruct JA4 afterward.

JA4 feasibility by setup pattern

Computing JA4 needs the raw ClientHello bytes, so feasibility is decided solely by where TLS is terminated (= who sees the client's ClientHello first) and unmask's mode (native / forward-auth). The backend app is irrelevant.

= node where unmask is installed   = TLS termination (where the ClientHello is seen)

Setup (client → …) JA4 unmask config
1. Front LB (co-located with unmask) + backend app — unmask terminates TLS
★●LB nginx (native) → httpdyesnone (plugin computes it)
★●LB nginx (forward-auth) → httpdno— nothing parses the ClientHello
★●LB apache (forward-auth) → httpdno
2. App-direct — unmask terminates TLS
★●nginx (native)yesnone
★●nginx (forward-auth)no
★●apache (forward-auth)no
3. Front CDN / LB terminates TLS (Cloudflare / GCP HTTPS LB / AWS ALB·CloudFront, …) + backend app
★CDN → ●LB nginx (native) → httpdyesselect under “trusted LB / CDN”
★CDN → ●LB nginx (forward-auth) → httpdyesselect under “trusted LB / CDN”
★CDN → ●LB apache (forward-auth) → httpdyesselect under “trusted LB / CDN”
4. Front CDN / LB terminates TLS + unmask direct
★CDN → ●nginx (native)yesselect under “trusted LB / CDN”
★CDN → ●nginx (forward-auth)yesselect under “trusted LB / CDN”
★CDN → ●apache (forward-auth)yesselect under “trusted LB / CDN”
  • native = nginx + unmask-plugin-nginx. The C module parses the ClientHello directly and computes JA4 (fastest, no subrequest, runs even on old distros like CentOS 6). Use this if you want JA4.
  • forward-auth = no plugin; verdicts delegated via auth_request / Apache mod_lua. It doesn't see TLS itself, so JA4 is empty unless the front CDN / LB forwards it (runs on UA / IP / rate / honeypot).
  • Apache has no native plugin (2.4's mod_ssl exposes no JA4 metadata; 2.6+ exposes metadata but unmask doesn't use it yet). For JA4 on Apache, the only path is forwarding from a front CDN / LB.
  • For forward-auth in rows 3–4, pick your front CDN / LB under “trusted LB / CDN” (same as native). unmask then renders a gate that adopts X-Client-JA4 only from that LB's IPs, and the shipped server.inc forwards the gated value automatically — no toggle, no manual wiring. See LB / CDN setup.

What happens if JA4 cannot be captured?

Even with an empty JA4, unmask still works. Bot detection continues with the following signals:

  • User-Agent classification — identifies known bots via a crawler / bot UA list of 250+ patterns
  • Official IP ranges — registers official ranges (Googlebot / Bingbot etc.) on the bypass list to avoid ranking accidents. Applied OR with the UA list (either match lets the request through)
  • rate-limit — escalates to a challenge when the per-IP × path threshold is exceeded
  • honeypot — bans clients that hit registered trap paths (e.g. CMS paths your site doesn't run)
  • behavioral CAPTCHA — a human-likeness score across 5 axes: mouseTrail / scroll / keyboard etc.
What you lose without JA4 is detection accuracy for stealth bots that impersonate legitimate browsers. A bot that cleanly fakes both its UA and IP can only be spotted by its TLS quirks (JA4). Conversely, as long as you can capture JA4, you can track the same tool through IP rotation and UA spoofing.

Summary — which setup to choose

  • Want to use JA4 fully → nginx + unmask-plugin-nginx (native mode). nginx must be terminating TLS
  • Have a front CDN / LB → extract JA4 there → X-Client-JA4 forward
  • Apache / plugin not possible → forward-auth mode. Run without JA4 using UA / IP / rate / honeypot

For install steps, see the install guide.