Beginner20 min

JA4H - HTTP Client Fingerprinting

JA4H fingerprints HTTP clients by analyzing the order and values of HTTP headers in requests. Different browsers, tools, and malware produce distinct header orderings that serve as a reliable fingerprint.

Prerequisites

  • Basic understanding of HTTP headers
  • Wireshark or tshark installed

What is JA4H?

JA4H creates a fingerprint from HTTP request headers. While User-Agent strings are easily spoofed, the order in which headers appear and the specific values of Accept-Language, Accept-Encoding, and other headers are much harder to fake. JA4H captures these patterns to identify HTTP clients.

Beyond User-Agent
User-Agent strings are trivially spoofed by malware. JA4H looks at the complete header ordering and values, making it much more difficult for attackers to impersonate legitimate browsers.

JA4H Format

ge11cn07enus_a5dfb2c3e8f1_b7e4a1d8f2c5_c8f2e1a4d7b3

ge11cn07enus

a section

Method, version, header count, Accept-Language

a5dfb2c3e8f1

b section

SHA-256 of sorted header field names

b7e4a1d8f2c5

c section

SHA-256 of header values (Accept, Accept-Encoding)

c8f2e1a4d7b3

d section

SHA-256 of cookie field names

Section A Components

  • ge - HTTP method (ge=GET, po=POST, pu=PUT)
  • 11 - HTTP version (11=HTTP/1.1, 20=HTTP/2)
  • cn - Cookie present (c) or not (n), Referer present (r) or not (n)
  • 07 - Number of headers
  • enus - First Accept-Language value (first 4 chars)

Header Ordering Analysis

Different HTTP clients send headers in different orders. Here is how common clients differ:

Chrome Header Order
GET /index.html HTTP/1.1
Host: example.com
Connection: keep-alive
sec-ch-ua: "Chromium";v="120"
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 ...
Accept: text/html,application/xhtml+xml
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
curl Header Order
GET /index.html HTTP/1.1
Host: example.com
User-Agent: curl/8.1.2
Accept: */*
Python requests Header Order
GET /index.html HTTP/1.1
Host: example.com
User-Agent: python-requests/2.31.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Malware Detection
Malware often mimics Chrome's User-Agent but uses Python's header ordering, or sends headers in an order no legitimate browser uses. JA4H catches this discrepancy.

Using JA4H

Wireshark Display Filters

JA4H filters
# Filter by JA4H fingerprint
ja4h.hash == "ge11cn07enus_a5dfb2c3e8f1_b7e4a1d8f2c5_c8f2e1a4d7b3"

# Show only POST requests
ja4h.hash matches "^po"

# Find HTTP/2 traffic
ja4h.hash matches "^..20"

# Find requests without cookies
ja4h.hash matches "^....n."

tshark Extraction

Extract JA4H fingerprints
# Extract JA4H from pcap
tshark -r capture.pcap -Y "http.request" \
  -T fields -e ip.src -e http.host -e ja4h.hash

# Count unique JA4H by client IP
tshark -r capture.pcap -Y "http.request" \
  -T fields -e ip.src -e ja4h.hash | sort | uniq -c | sort -rn

# Cross-reference with User-Agent
tshark -r capture.pcap -Y "http.request" \
  -T fields -e ip.src -e http.user_agent -e ja4h.hash

Hands-On Exercise

Step 1: Capture HTTP Traffic

tshark -i eth0 -f "tcp port 80" -w http_capture.pcap -c 200

Step 2: Generate Traffic from Different Clients

# Using curl
curl http://example.com/

# Using wget
wget -q http://example.com/ -O /dev/null

# Using Python
python3 -c "import requests; requests.get('http://example.com/')"

Step 3: Compare JA4H Fingerprints

Extract and compare JA4H fingerprints from each client. Note how each produces a unique fingerprint despite all accessing the same resource. Pay attention to the header count and Accept-Language differences.

Lab Complete
You can now fingerprint HTTP clients. Next, explore JA4T to fingerprint TCP clients at the transport layer.