Documentation
¶
Overview ¶
Package ja4 implements JA4+ network fingerprinting algorithms in pure Go.
JA4+ is a suite of methods for creating human and machine-readable fingerprints of network traffic. This package provides ComputeJA4 (TLS client fingerprinting) and ComputeJA4H (HTTP client fingerprinting), the two methods most relevant for HTTP client libraries.
Fingerprint Format ¶
All JA4+ fingerprints use an a_b_c locality-preserving format with three sections, allowing partial matching on individual parts independently.
- Section a: structured metadata (protocol, version, SNI, counts, ALPN)
- Section b: hash of cipher suites (JA4) or header names (JA4H)
- Section c: hash of extensions + signature algorithms (JA4) or cookie data (JA4H)
JA4 — TLS Client Fingerprint ¶
The ComputeJA4 function produces a fingerprint from a TLS ClientHello:
t13d1516h2_8daaf6152771_e5627efa2ab1 - t: protocol (t=TLS, q=QUIC, d=DTLS) - 13: highest TLS version (13=TLS 1.3, 12=TLS 1.2) - d: SNI present (d=domain, i=IP) - 15: cipher suite count (GREASE excluded) - 16: extension count (GREASE excluded) - h2: first+last char of first ALPN protocol - 8daaf6152771: SHA-256 hash of sorted cipher suites (truncated to 12 hex chars) - e5627efa2ab1: SHA-256 hash of sorted extensions + sig algorithms (truncated to 12 hex chars)
JA4H — HTTP Client Fingerprint ¶
The ComputeJA4H function produces a fingerprint from HTTP request properties:
ge11nn03enus_1c8f3b0e29d1_000000000000_000000000000 - ge: first 2 chars of method, lowercased - 11: HTTP version (10=1.0, 11=1.1, 20=2, 30=3) - n: no cookies (c=present) - n: no referer (r=present) - 03: header count (excluding Cookie, Referer) - enus: first 4 chars of Accept-Language - 1c8f3b0e29d1: SHA-256 hash of sorted header names (truncated to 12 hex chars) - 000000000000: SHA-256 hash of sorted cookie names (12 zeros if no cookies) - 000000000000: SHA-256 hash of cookie values in sorted-by-name order
GREASE Handling ¶
TLS GREASE (Generate Random Extensions And Sustain Extensibility) values are filtered from all counts and hashes. Use IsGREASE to check individual values and FilterGREASE to remove them from a slice.
Integration with aoni ¶
For automatic JA4 fingerprinting through the aoni HTTP client, use:
[aoni.WithTLSFingerprint] to emulate browser TLS handshakes
[aoni.WithJA4Callback] to receive fingerprints via a callback
[aoni.TraceJA4] to populate [aoni.TraceInfo] with both JA4 and JA4H
info := &aoni.TraceInfo{} client := aoni.NewClient(nil). WithTLSFingerprint(aoni.BrowserChrome). WithJA4Callback(func(r ja4.JA4Report) { fmt.Println("TLS JA4:", r.JA4) })
client.Get(ctx, "/path", aoni.TraceJA4(info)) fmt.Println("HTTP JA4H:", info.JA4.JA4H)
Reference Implementation ¶
This package implements the algorithms described in the FoxIO JA4+ technical specification. The fingerprint format is designed to be resilient against cipher stunting and extension randomization used by modern browsers.
Index ¶
- func ComputeJA4(cipherSuites []uint16, extensions []uint16, supportedVersions []uint16, ...) string
- func ComputeJA4H(method, proto string, headers []string, hasCookie, hasReferer bool, ...) string
- func FilterGREASE(vals []uint16) []uint16
- func IsGREASE(v uint16) bool
- func ParseExtensionsFromRaw(raw []byte) (extensions, sigAlgorithms []uint16)
- type Report
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ComputeJA4 ¶
func ComputeJA4( cipherSuites []uint16, extensions []uint16, supportedVersions []uint16, sni bool, alpnProtocols []string, sigAlgorithms []uint16, ) string
ComputeJA4 computes a JA4 TLS client fingerprint.
Parameters:
- cipherSuites: raw cipher suite IDs from ClientHello
- extensions: extension IDs in wire order
- supportedVersions: from supported_versions extension
- sni: whether SNI extension is present
- alpnProtocols: ALPN protocol strings
- sigAlgorithms: signature algorithm IDs in wire order (may be nil)
The fingerprint format is: {protocol}{version}{sni}{cipher_count}{ext_count}{alpn}_{cipher_hash}_{ext_hash}
func ComputeJA4H ¶
func ComputeJA4H( method, proto string, headers []string, hasCookie, hasReferer bool, acceptLanguage string, cookieNames, cookieValues []string, ) string
ComputeJA4H computes an HTTP client fingerprint.
Parameters:
- method: HTTP method (e.g. "GET", "POST")
- proto: HTTP protocol version (e.g. "HTTP/1.1", "HTTP/2")
- headers: header names in original order (excluding Cookie, Referer, pseudo-headers)
- hasCookie: whether Cookie header is present
- hasReferer: whether Referer header is present
- acceptLanguage: Accept-Language header value
- cookieNames: cookie names sorted by name
- cookieValues: cookie values in sorted-by-name order
The fingerprint format is: {method}{version}{cookie}{referer}{header_count}{lang}_{headers_hash}_{cookie_names_hash}_{cookie_values_hash}
func FilterGREASE ¶
FilterGREASE returns a new slice with GREASE values removed.
func ParseExtensionsFromRaw ¶
ParseExtensionsFromRaw parses extension IDs from a raw TLS ClientHello message in wire order. It also extracts signature algorithms if present.
The raw format is:
2 bytes: handshake type (0x0300) + length 2 bytes: client version 32 bytes: random 1 byte + session ID: variable 2 bytes + cipher suites: variable 1 byte + compression methods: variable 2 bytes: extensions total length then: extension entries (2-byte ID + 2-byte length + data)
Types ¶
type Report ¶
type Report struct {
// JA4 is the TLS client fingerprint (e.g. "t13d1516h2_8daaf6152771_e5627efa2ab1").
JA4 string
// JA4H is the HTTP client fingerprint (e.g. "ge11cn04en04_9ed1ff1f7b03_cd8dafe26982").
JA4H string
// Protocol is the TLS protocol prefix: "t" (TLS), "q" (QUIC), "d" (DTLS).
Protocol string
// Version is the negotiated TLS version code: "13" (TLS 1.3), "12" (TLS 1.2), etc.
Version string
// SNI indicates SNI presence: "d" (domain name) or "i" (IP address).
SNI string
// CipherCount is the number of cipher suites (GREASE excluded).
CipherCount int
// ExtCount is the number of extensions (GREASE excluded).
ExtCount int
// ALPN is the first and last alphanumeric characters of the first ALPN protocol.
ALPN string
}
Report holds both TLS (JA4) and HTTP (JA4H) fingerprints computed from a request.