Skip to content

Traffic Filtering by Fingerprints

symstu-tempesta edited this page Jun 18, 2025 · 5 revisions

Overview

Tempesta FW provides traffic filtering by JA5 clients fingerprints. Currently TLS (JA5t) and HTTP (JA5h) fingerprints are supported. The filtering is applied by connections and records/messages number per second.

The fingerprint computation and filtration are enabled with ja5t and ja5h configuration options.

As opposed to JA3 and JA4 hashes using cryptographic MD5 and SHA-256 hashes, JA5 employs faster hashing more suitable for automatic classification (machine learning) usage.

The hashes are commuted as:

TLS (ja5t)

  1. 1 bit: TLS version (1.2 or 1.3, constant for now, left 1.3 for #1031 )
  2. 1 bit: abbreviated handshake
  3. 1 bit: found vhost for SNI
  4. 3 bits: ALPN: h2, http/1.1,http/1.1,h2, h2,http/1.1, other, zero value for empty
  5. alignment to 1 byte
  6. 2 bytes: sum * 11 + cipher_suite (11 is just a small prime, relatively far from a power of 2). This scheme represents the order of cipher suites.
  7. 2 bytes: sum * 11 + extension_type
  8. 2 bytes: sum * 11 + elliptic_curve

HTTP (ja5h)

  1. 1 bit: http version (h1 or h2)
  2. 5 bits: HTTP method (tfw_http_meth_t value)
  3. 5 bits: number of Cookie values (all bits set for 31 and more cookies, within one or several headers)
  4. 6 bits: number of headers (all bits set for 63 and more headers)
  5. 1 bit: has Referer
  6. alignment to 3 bytes
  7. 4 bytes: sum * 11 + header, where header is a 4 bytes HTTP/1 header prefix or value from static of decoded dynamic table value for HTTP/2

If JA5 is configured, Tempesta FW computes the TLS and HTTP hashes and logs them into the access log.

Configuration

The following explains how to use ja5 directives in the configuration, along with available options and examples

ja5t

Syntax:         ja5t <storage_size> { }
Default:        ja5t 2097152;
Context:        global
Reconfig:       true
Repeat:         false

storage_size is the size of an internal LRU storage of online clients' fingerprints. The value must be a multiple of 2097152 bytes (2MB) and is optional. Default is 25 * 2^21 bytes(50 MB).

Minimum is 2^21 bytes.

Maximum is 128849018880 bytes (120 GB).

Examples

ja5t storage_size=2097152 {
}

ja5t {
}

ja5t {
    hash deadbeef12345678 10 1000;
    hash aeae463fe56e8e87 10 1000000;
}

This empty configuration says to Tempesta FW that it has to compute fingerprints for all clients and compute their connection, HTTP requests and/or TLS records rates. Tempesta FW does not block anything with an empty JA5 configuration, but can immediately drop TLS connections and HTTP requests according to reloaded configuration with specific hash values.

ja5h

Has the same syntax as ja5t.

Syntax:         hash <hash_string> <connections_per_second> <records_per_second>;
Default:        none
Context:        ja5h, ja5t
Reconfig:       true
Repeat:         true

hash_string is a fingerprint itself represented by a hex string without any prefixes. The value may be retrieved from dmesg, mmap access log buffer or Clickhouse database supplied by tfw_logger process. No default value.

connections_per_second is an allowed number of connections for clients identified by hash_string. No default value.

records_per_second is an allowed number of TLS records (if inside ja5t) or HTTP messages (if inside ja5h). No default value.

Examples

hash deadbeef12345678 10 1000;
hash aeae463fe56e8e87 0 0;

Zero values for connections_per_second and records_per_second mean that TLS connections or HTTP requests having such hashes will be blocked.

Dynamic On-the-Fly Blocking

In cases of high traffic and numerous hashes to block, updating and reloading the main configuration may not be practical. It's possible to encounter thousands of blocking hashes, which would make the configuration file difficult to read and maintain.

For such situations, it's useful to separate the blocking hashes into a different file and include that file in the main configuration. Moreover, this approach allows you to organize hashes into logical groups, each in its own file.

Here is an example:

/etc/tempesta/tempesta_fw.conf

listen 443 proto=https,h2;
access_log dmesg;
server 127.0.0.1:8000;

...

ja5t {
    !include /etc/tempesta/ja5t/
}
ja5h {
    !include /etc/tempesta/ja5h/
}

...    

/etc/tempesta/ja5t/high-risk.conf

hash b7007c90000 1 1;
hash cd00ade0000 1 1;
....

/etc/tempesta/ja5t/high-risk.conf

hash 55cbf8cce0170011 1 1;
hash 113fa8cce1120000 1 1;
...

With such a configuration, we can easily add new blocking records or remove existing ones.

To block a new hash

echo "hash b7007c90000 1 1;" >> /etc/tempesta/ja5t/high-risc.conf
service tempesta reload

echo "hash b7007c90000 1 1;" >> /etc/tempesta/ja5t/new-group.conf
service tempesta reload

To unblock a hash

sed -i "/b7007c90000/d" /etc/tempesta/ja5t/high-risc.conf
service tempesta reload
Clone this wiki locally