Overview
TLS fingerprinting identifies clients by the parameters they send during the TLS handshake (ClientHello message). Different browsers and operating systems use different TLS configurations.
JA3 Fingerprint
JA3 is a hash computed from the TLS ClientHello:
JA3 = MD5(Ciphers + Extensions + EllipticCurves + EllipticCurvePointFormats)
Where each field is concatenated:
ciphers: 49199,49196,52393,... (list of cipher suite IDs)
extensions: 0,23,65281,... (list of extension type IDs)
curves: 29,23,24,... (list of supported groups)
formats: 0 (EC point formats)
Example JA3 Hashes
| Browser | JA3 |
|---|---|
| Chrome 120 (Windows 11) | 6734f37431670b3ab4292b8f60f29984 |
| Firefox 121 (Windows 11) | d1b8d7e1c7c8b0a6b1a2c3d4e5f6a7b8 |
| Safari 17 (macOS 14) | 9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d |
| Chrome 120 (Android 14) | b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6 |
JA4 Fingerprint (Next Generation)
JA4 extends JA3 by also analyzing:
- TLS version
- SNI presence
- ALPN protocols
- HTTP/2 settings
Format: tls_version.ciphers.extensions.sni.alpn
HTTP/2 Fingerprinting
HTTP/2 connections reveal additional fingerprints via:
- SETTINGS frame parameters (MAX_CONCURRENT_STREAMS, INITIAL_WINDOW_SIZE, etc.)
- WINDOW_UPDATE timing
- PING frame behavior
- Priority frame structure
Spoofing TLS Fingerprint
Tools like TLSMask and utls can modify the ClientHello to mimic another browser:
Actual ClientHello [TLS Spoofer] Mimicked ClientHello Server
Approach
- Capture a real ClientHello from the target browser/OS
- Store as a template
- Modify outbound ClientHello to match the template parameters
- Forward to destination
Implications for Obscura:
- TLS spoofing can be done at the proxy level, unlike Canvas/WebGL/audio
- Go has
utlslibrary (fork ofcrypto/tlswith ClientHello customization) - Rust has
tls-parser+ custom TLS implementation - The proxy must terminate TLS anyway for MITM, so the TLS fingerprint seen by the server will be the proxy's Go/Rust TLS implementation unless consciously spoofed
Conclusions
- TLS fingerprinting (JA3/JA4) is tractable at the proxy level
- Go's
utlslibrary provides direct ClientHello manipulation - Must be a core feature of Obscura
- Without TLS spoofing, the proxy's own TLS library would leak that a proxy is in use