Adam Cassar

Co-Founder

8 min read

A network fingerprint is a useful rate-limit key. It is a poor verdict.

That sounds like a small distinction, but it changes how a control behaves. A limit keyed only by source IP can miss a distributed scraper moving through thousands of addresses. Add a TLS or HTTP fingerprint and the requests may fall into a recognisable cohort. The operator can count and compare them even while the IPs rotate.

The same key can also group thousands of ordinary users running the same browser release. If the control reads “this fingerprint is a bot” and blocks it everywhere, the grouping feature has become a false-positive multiplier.

The practical job is to use the fingerprint where grouping helps, then make the decision from the route, behaviour and consequence. This article sets out one way to do that.

Start with the route, not the fingerprint

A request for a cached image and a request to submit a password do not deserve the same policy. Neither do a search request and an export that starts an expensive database job.

Before adding fingerprint data, classify the routes that matter:

  • what the request can change or disclose;
  • whether it consumes scarce application or origin capacity;
  • whether a legitimate user can retry safely;
  • whether the client can complete a challenge;
  • which identity is available, such as an account, session, API key or no identity at all;
  • what an incorrect block would cost.

This route map sets the response. An unfamiliar cohort fetching public content might only be worth observing. The same cohort attempting passwords across many accounts may justify a tight shared limit. A fingerprint mismatch on an authenticated payment action may call for step-up verification rather than a network block.

Route sensitivity also prevents a common emergency mistake: applying a site-wide rule because an attack was visible on one endpoint. Narrow rules are easier to explain, test and remove.

Use the fingerprint as a cohort key

JA3, JA4 and Cisco Mercury do not identify a person or device. Each method selects and normalises protocol fields, then groups connections that look equivalent under those rules. Our same-ClientHello lab shows how three methods produce three different representations from one handshake.

That makes the fingerprint useful for questions such as:

  • Are login failures arriving from many IP addresses but one narrow set of client stacks?
  • Did an expensive API route suddenly attract a new protocol cohort?
  • Does traffic claiming to be a browser have a consistent TLS, HTTP and header shape?
  • Did a cohort disappear after an abusive tool changed version, or did the fingerprinting rules change underneath us?

The key should be composite. A workable rate counter might resemble:

route_class + fingerprint_method + fingerprint_version + fingerprint_value

Depending on the abuse case, add an account, tenant, API credential, ASN or country. Do not throw every field into every key. An over-specific key divides a distributed campaign into buckets too small to see; an over-broad key combines unrelated users.

Run a few candidate keys in observation mode and measure their bucket sizes. Look at both tails. A key that places half the site's users in one bucket is too blunt for direct enforcement, however suspicious that bucket looked during one incident.

Record where the value came from

Fingerprint provenance is operational data, not documentation trivia.

At an origin behind a CDN or reverse proxy, the visible TLS connection may belong to that intermediary. A fingerprint forwarded in a header might describe the original client-facing connection, or it might describe a later hop. The receiving service cannot tell from the hash alone.

For each event, keep at least:

method:       ja4
version:      pinned implementation or rule version
value:        t13d..._..._...
capture:      client-facing edge
source:       named collector or trusted forwarding hop
observed_at:  timestamp
policy:       policy identifier and revision
action:       observe, challenge, rate-limit or block

Where the format permits it, retaining the selected raw fields or unhashed representation makes later comparison much easier. Cisco Mercury's full Network Protocol Fingerprint is structured and versioned; its optional hash is a compact nickname that discards that structure. JA4 publishes both a canonical hashed form and a raw JA4_r form. The details are in the Mercury NPF specification and JA4 technical specification.

Trust the forwarding path as deliberately as any other security metadata. Strip client-supplied copies at the boundary, set the authoritative value there, and record the hop that produced it. Otherwise an attacker may be able to choose the value used by the policy.

Use an action ladder

Bot controls work better with space between “allow” and “block”. A simple ladder is observe, challenge, rate limit, then block. It is not a mandatory sequence for every request; it is a way to match disruption to confidence.

Observe

Observation is the right first action for a new cohort, a changed implementation or a weak hypothesis. Record volume, routes, account outcomes, response codes, request cost and how the cohort overlaps with known legitimate clients.

Set an end date before starting. “Log this for seven days and review on Monday” produces a decision. “Log this” often produces another permanent stream nobody owns.

Challenge

A challenge asks the client for more evidence. It can separate some interactive browsers from simple automation, but it is not a universal test of humanity. Browser automation can complete challenges; privacy software, accessibility tools and broken JavaScript can make legitimate users fail them.

Use challenges where the client can reasonably complete one and where failure has a safe recovery path. They are a poor fit for machine-to-machine APIs unless the protocol already defines an authentication or proof step.

Rate limit

Rate limiting fits repeated or costly behaviour. Count a cohort against the route it is affecting, then layer in the identities that make sense for that route. For example:

login:  fingerprint + account + failed outcome
search: fingerprint + route + request cost
API:    fingerprint + tenant or credential + operation

A limit should say what it protects. Requests per minute is sometimes enough. Expensive operations may need a cost-weighted budget. Login protection may count failed attempts while allowing successful account recovery to proceed. Distributed abuse may need a cohort-wide ceiling plus per-account and per-IP limits so that no single key carries the whole policy.

Return an explicit response and keep the retry behaviour predictable. The HTTP 429 Too Many Requests status was defined for rate limiting in RFC 6585, including the option to send Retry-After. Clients still need sensible backoff, and operators need to watch whether retries are making origin pressure worse.

Block

Block when the evidence is strong, the harm is current, and a less disruptive action cannot protect the route. Good candidates include a confirmed exploit tool hitting the vulnerable route, a cohort causing active availability loss, or repeated abuse that has failed narrower controls.

Keep the scope bounded: fingerprint method and version, affected route, relevant behaviour, start time, owner and expiry. A bare fingerprint deny-list with no incident context is hard to audit and tends to outlive its evidence.

For a broader mapping of actions to evidence, see Network Fingerprint Signals and Security Decisions and Network Fingerprinting for Rate Limiting.

Combine evidence before increasing friction

The most useful policy does not ask whether a fingerprint is good or bad. It asks whether several observations agree.

Consider a login campaign. The source addresses rotate through residential networks. The TLS cohort is common because the tool drives a real browser. The fingerprint alone is weak. But the same traffic may attempt many accounts, reuse a route sequence, fail at a high rate, omit normal session history and arrive at a cadence unlike ordinary users. Together those observations justify a shared limit or challenge.

Now reverse the example. A rare TLS cohort signs in successfully to one account from its usual region, follows a normal route sequence and maintains an established session. Rarity does not add much. Blocking it would mostly punish an unusual client.

This is also the line between a format and a detection system. JA4 defines a fingerprint. Mercury defines fingerprint representations and includes separate analysis components. Any claim such as “this is Chrome”, “this is a scraper” or “this is malicious” comes from surrounding data and inference, not from the fingerprint characters themselves. A Network Fingerprint Is a Cohort, Not a Client explains that boundary in more detail. Fingerprints Are Evidence, Not Identity covers the same problem across browser, network and behavioural fingerprints.

Expect versions and populations to drift

Browsers ship, TLS libraries change defaults, mobile applications update unevenly and attack tools copy popular handshakes. Fingerprint implementations also change their parsing rules. Store the method and implementation version so client drift can be separated from detector drift.

Before changing an implementation, calculate old and new values side by side on a sample. Compare cohort sizes and known-good traffic by route. A partner API, mobile application and public website have different expected populations; a global label may be irrelevant to the local control.

Put expiry and rollback in the policy

Every enforcement rule needs an owner, reason, expiry and removal condition. Before enabling it, record request volume, successful transactions, challenges, 429 responses and origin health. Compare the same measures afterwards. A falling attack rate is not success if legitimate completion falls with it.

When a false positive appears, retain the fingerprint version, capture point, contributing evidence, route, identity, policy revision and rollback result. That record shows whether to change a threshold, split a route class, add an exception, demote the action or remove the fingerprint from the key.

A deployable first policy

For a first production use, choose one abused route. Generate a versioned fingerprint at a trusted capture point, log it beside the route and outcome, and observe cohort sizes long enough to include normal variation. Then choose one reversible action with success measures, rollback and an expiry.

The fingerprint has done its job when it helps a team see and control a group of requests that an IP-only rule would miss. It has exceeded its job when the group is treated as proof of a client, person or intent.