JAx Fingerprint Plugin
Description
The JAx Fingerprint plugin generates client fingerprints based on the JA4+ or JA3 algorithms designed by John Althouse.
Fingerprints can be used for:
Client identification and tracking
Bot detection and mitigation
Security analytics and threat intelligence
Understanding client implementation patterns
Plugin Configuration
The plugin is configured either with a YAML file that is passed as the plugin's only argument, or with command-line options (see Command-Line Configuration). A relative path to a configuration file is resolved from the Traffic Server configuration directory. You can use the plugin as a global plugin, a remap plugin, or both.
To use the plugin as a global plugin, add the following line to plugin.config:
jax_fingerprint.so jax_fingerprint.yaml
To use the plugin as a remap plugin, append the following to a remap rule in remap.config:
@plugin=jax_fingerprint.so @pparam=jax_fingerprint_remap.yaml
To use the plugin in a hybrid setup, load it both in plugin.config and in
remap.config, without setting standalone in either configuration. See
Plugin Behavior for how to choose between these setups.
When loaded through plugin.yaml, the configuration can also be provided inline through the
config field:
plugins:
- path: jax_fingerprint.so
config: |
jax_fingerprint:
fingerprints:
- method: JA4
standalone: true
header: x-ja4
Configuration File
The configuration file contains a single jax_fingerprint map with a fingerprints list.
Each entry in the list configures one fingerprinting method. A single configuration file can list
as many methods as needed, and every method listed is generated independently. Each method can be
listed only once per export registry, and each log_field symbol can be used only once. For example, the
following global configuration adds JA3, JA4, and JA4H fingerprints to every request:
jax_fingerprint:
fingerprints:
- method: JA3
standalone: true
header: x-ja3
- method: JA4
standalone: true
header: x-ja4
log_filename: jax_ja4
- method: JA4H
standalone: true
header: x-ja4h
Unrecognized keys, duplicate keys, and invalid values are reported in diags.log and cause the configuration
to be rejected. A rejected remap configuration fails the remap.config load.
Each fingerprint entry supports the following keys.
methodThe fingerprinting method to use:
JA4,JA4H, orJA3. This key is required.standalonetrueorfalse. The default isfalse. Set this totruewhen you use either the global setup or the remap setup. Leave it unset in both configurations when you use the hybrid setup.modeWhat to do when a client request already contains the headers named by
headerand/orvia_header. Available values areoverwrite,keep, andappend. The default isoverwrite.headerThe name of the header field where the plugin stores the generated fingerprint value. If not specified, the fingerprint header is not added.
via_headerThe name of the header field where the plugin stores the generated fingerprint-via value. If not specified, the fingerprint-via header is not added.
servernamesA list of server names for which the plugin generates fingerprints. If not specified, the plugin generates fingerprints for any server name. This key is supported only for the methods that fingerprint the TLS handshake, JA3 and JA4. A remap instance supports it only with
standalone; otherwise the remap instance uses the fingerprint generated by the global instance, so setservernameson the global instance instead. For example:servernames: - abc.example - xyz.example
exportThe name of the registry in which generated fingerprints are published for other plugins. See Fingerprint Registry Export. The default registry name is
jax_fingerprint.log_filenameThe filename for the plugin log file. If not specified, log output is suppressed. See Log Output.
log_fieldRegisters a custom log field with the given symbol name that can be used in
logging.yamllog formats. The log field outputs the generated fingerprint value for each transaction. If not specified, no custom log field is registered.For example, with
log_field: jaxja4you can use%<jaxja4>in a log format string inlogging.yaml.注釈
This key is only supported in the configuration loaded from
plugin.config. Log fields are global and must be registered before log formats are parsed at startup. If you use a remap-only setup, you must also load the plugin globally withlog_fieldto register the log field.
Command-Line Configuration
Instead of a configuration file, the plugin accepts command-line options that configure a single
fingerprint. To generate more than one fingerprint this way, list the plugin once per method in
plugin.config, or once per method on a remap rule. Traffic Server logs a warning when the same plugin
is loaded more than once from plugin.config; a configuration file configures any number of
methods from a single line instead.
Each option corresponds to the configuration file key of the same name, with dashes in place of underscores:
Option |
Configuration file key |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
For example, the following plugin.config lines add JA3 and JA4 fingerprints to every
request:
jax_fingerprint.so --method JA3 --standalone --header x-ja3
jax_fingerprint.so --method JA4 --standalone --header x-ja4
and the following remap rule adds a JA4H fingerprint to the requests that match it:
map / http://origin.example/ @plugin=jax_fingerprint.so @pparam=--method=JA4H @pparam=--standalone @pparam=--header=x-ja4h
A plugin configured with command-line options has no configuration file to reload, so changing its
settings requires a restart for plugin.config, or a remap.config reload for a remap
rule.
Reloading the Configuration
A configuration file loaded from plugin.config can be re-read without restarting Traffic Server by
sending the plugin a message:
traffic_ctl plugin msg jax_fingerprint.reload
The following keys take effect for new connections and transactions after a successful reload:
servernamesheadervia_headermode
The other keys configure hooks, registries, log files, and log fields that are set up when Traffic Server
starts, so they can only be changed with a restart. The list of fingerprints must contain the same
entries, in the same order, with the same method, standalone, export,
log_filename, and log_field values as the configuration loaded at startup. A reload that
changes any of these, or that fails to load, is rejected with an error in diags.log and the
current configuration stays in effect. A successful reload is noted in diags.log. If the
plugin is listed more than once in plugin.config, each line reloads its own configuration
file.
For example, to start fingerprinting connections for a new service, add its server name to the list and reload:
jax_fingerprint:
fingerprints:
- method: JA4
servernames:
- abc.example
- xyz.example
- new-service.example
Remap configurations are reloaded along with remap.config and accept changes to any key.
Editing a remap configuration file and running traffic_ctl config reload reloads it, even if
remap.config itself is unchanged.
Plugin Behavior
Global plugin setup
- Global plugin setup is the best if you:
Need a fingerprint on every request
Remap plugin setup
- Remap plugin setup is the best if you:
Need a fingerprint only on specific paths, or
Cannot use Global plugin setup
注釈
For JA3 and JA4, fingerprints are always generated at the beginning of connections. Using remap plugin setup only reduces the overhead of adding HTTP headers and logging.
Hybrid setup
- Hybrid setup is the best if you:
Need a fingerprint only for specific server names (in TLS SNI extension), and
Need a fingerprint only on specific paths
Fingerprint Registry Export
Fingerprints with the same storage type and export name contribute to one registry, so a
ClientHello fingerprint is computed once even when more than one plugin uses it. For example:
jax_fingerprint:
fingerprints:
- method: JA3
export: security.fingerprints
- method: JA4
export: security.fingerprints
Consumers should use an explicit registry name to make the relationship clear, and must be loaded
after the JAx plugin in plugin.config.
The export registry is an in-process, read-only view stored in a named Traffic Server user-argument slot. The registry contains length-delimited method/value entries plus a magic value, ABI version, and structure sizes, allowing consumers to reject incompatible layouts. JAx owns the registry and strings for the lifetime of the connection or transaction; consumers must not modify them or retain their pointers.
Connection-based methods such as JA3 and JA4 use a VConn registry. Request-
based methods such as JA4H use a transaction registry and therefore cannot be
consumed at a ClientHello hook. If your organization implements custom JA
methods, these also can be exported through the same registry without adding a
method-specific API to ts.h.
Log Output
The plugin outputs a log file in the Traffic Server log directory (typically /var/log/trafficserver/) if a log filename is
specified by the log_filename key.
Log Format:
[timestamp] Client: <address> <method_name>: <fingerprint>
Example:
[Jan 29 10:15:23.456] Client: 192.168.1.100 JA4: t13d1516h2_8daaf6152771_b186095e22b6
[Jan 29 10:15:24.123] Client: 10.0.0.50 JA4: t13d1715h2_8daaf6152771_02713d6af862
Using HTTP Headers in Origin Requests
Origin servers can access the generated fingerprint through the injected HTTP header. This allows the origin to:
Make access control decisions based on client fingerprints
Log fingerprints for security analysis
Track client populations and TLS implementation patterns
The fingerprint-via header allows origin servers to track which Traffic Server proxy handled the request when multiple proxies are deployed.
Debugging
To enable debug logging for the plugin, set the following in records.yaml:
records:
diags:
debug:
enabled: 1
tags: jax_fingerprint
Requirements
Traffic Server must be built with TLS support (OpenSSL or BoringSSL) if you use JA3 or JA4
See Also
JA3 Technical Specification: https://github.com/FoxIO-LLC/ja3
JA4+ Technical Specification: https://github.com/FoxIO-LLC/ja4
Example Configurations
Enable JA4 fingerprinting for every request
This configuration adds an x-ja4 header to every request and logs each fingerprint to the
jax_ja4 log file.
plugin.config:
jax_fingerprint.so jax_fingerprint.yaml
jax_fingerprint.yaml:
jax_fingerprint:
fingerprints:
- method: JA4
standalone: true
header: x-ja4
via_header: x-ja4-via
log_filename: jax_ja4
Enable JA4H fingerprinting on a single remap rule
This configuration adds an x-ja4h header only to requests that match the remap rule.
remap.config:
map https://www.example.com/ https://origin.example.com/ @plugin=jax_fingerprint.so @pparam=jax_ja4h.yaml
jax_ja4h.yaml:
jax_fingerprint:
fingerprints:
- method: JA4H
standalone: true
header: x-ja4h
Enable JA4 fingerprinting by hybrid (global + remap) setup
This configuration adds an x-my-ja4 header to requests that match the remap rule if the connection was established for either abc.example or xyz.example. The global plugin generates the fingerprint when the TLS connection is established, and the remap plugin adds the header.
plugin.config:
jax_fingerprint.so jax_fingerprint.yaml
jax_fingerprint.yaml:
jax_fingerprint:
fingerprints:
- method: JA4
servernames:
- abc.example
- xyz.example
remap.config:
map / http://origin.example/ @plugin=jax_fingerprint.so @pparam=jax_fingerprint_remap.yaml
jax_fingerprint_remap.yaml:
jax_fingerprint:
fingerprints:
- method: JA4
header: x-my-ja4
Log multiple fingerprints in the access log
This configuration registers custom log fields for JA3, JA4, and JA4H fingerprints and records them in the access log.
plugin.config:
jax_fingerprint.so jax_fingerprint.yaml
jax_fingerprint.yaml:
jax_fingerprint:
fingerprints:
- method: JA3
log_field: jaxja3
- method: JA4
log_field: jaxja4
- method: JA4H
standalone: true
log_field: jaxja4h
logging.yaml:
logging:
formats:
- name: fingerprints
format: '%<chi> %<cqu> JA3=%<jaxja3> JA4=%<jaxja4> JA4H=%<jaxja4h>'
logs:
- filename: fingerprints
format: fingerprints