Skip to content

Commit 910f3e5

Browse files
authored
Add jax_fingerprint plugin (#12995)
This adds an experimental plugin jax_fingerprint. The basic functionality is the same as ja3_fingerprint and ja4_fingerprint, but the configuration is more flexible.
1 parent 3d5bbd8 commit 910f3e5

45 files changed

Lines changed: 4885 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cmake/ExperimentalPlugins.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ auto_option(HTTP_STATS FEATURE_VAR BUILD_HTTP_STATS DEFAULT ${_DEFAULT})
4343
auto_option(ICAP FEATURE_VAR BUILD_ICAP DEFAULT ${_DEFAULT})
4444
auto_option(INLINER FEATURE_VAR BUILD_INLINER DEFAULT ${_DEFAULT})
4545
auto_option(JA4_FINGERPRINT FEATURE_VAR BUILD_JA4_FINGERPRINT VAR_DEPENDS DEFAULT ${_DEFAULT})
46+
auto_option(JAX_FINGERPRINT FEATURE_VAR BUILD_JAX_FINGERPRINT VAR_DEPENDS DEFAULT ${_DEFAULT})
4647
auto_option(
4748
MAGICK
4849
FEATURE_VAR

doc/admin-guide/plugins/index.en.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ directory of the |TS| source tree. Experimental plugins can be compiled by passi
179179
Hook Trace <hook-trace.en>
180180
ICAP <icap.en>
181181
JA4 Fingerprint <ja4_fingerprint.en>
182+
JAx Fingerprint <jax_fingerprint.en>
182183
Maxmind ACL <maxmind_acl.en>
183184
Memcache <memcache.en>
184185
Memory Profile <memory_profile.en>
@@ -236,6 +237,9 @@ directory of the |TS| source tree. Experimental plugins can be compiled by passi
236237
:doc:`JA4 Fingerprint <ja4_fingerprint.en>`
237238
Calculates JA4 Fingerprints for incoming TLS traffic.
238239

240+
:doc:`JAx Fingerprint <jax_fingerprint.en>`
241+
Calculates JAx Fingerprints.
242+
239243
:doc:`MaxMind ACL <maxmind_acl.en>`
240244
ACL based on the maxmind geo databases (GeoIP2 mmdb and libmaxminddb)
241245

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
.. Licensed to the Apache Software Foundation (ASF) under one
2+
or more contributor license agreements. See the NOTICE file
3+
distributed with this work for additional information
4+
regarding copyright ownership. The ASF licenses this file
5+
to you under the Apache License, Version 2.0 (the
6+
"License"); you may not use this file except in compliance
7+
with the License. You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing,
12+
software distributed under the License is distributed on an
13+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
KIND, either express or implied. See the License for the
15+
specific language governing permissions and limitations
16+
under the License.
17+
18+
.. include:: ../../common.defs
19+
20+
.. _admin-plugins-jax-fingerprint:
21+
22+
JAx Fingerprint Plugin
23+
**********************
24+
25+
Description
26+
===========
27+
28+
The JAx Fingerprint plugin generates client fingerprints based on the JA4+ or JA3 algorithms designed by John Althouse.
29+
30+
Fingerprints can be used for:
31+
32+
* Client identification and tracking
33+
* Bot detection and mitigation
34+
* Security analytics and threat intelligence
35+
* Understanding client implementation patterns
36+
37+
38+
Plugin Configuration
39+
====================
40+
41+
You can use the plugin as a global plugin, a remap plugin, or both.
42+
43+
To use the plugin as a global plugin, add the following line to :file:`plugin.config`::
44+
45+
jax_fingerprint.so --standalone
46+
47+
To use the plugin as a remap plugin, append the following line to a remap rule on :file:`remap.config`::
48+
49+
@plugin=jax_fingerprint.so @pparam=--standalone
50+
51+
To use the plugin in a hybrid setup (both global and remap plugin), configure it in both :file:`plugin.config` and
52+
:file:`remap.config` without ``--standalone`` option.
53+
54+
55+
.. option:: --standalone
56+
57+
This option enables you to use the plugin as either a global plugin, or a remap plugin. In other
58+
words, the option needs to be specified if you do not use the hybrid setup.
59+
60+
.. option:: --method <JA4|JA4H|JA3>
61+
62+
Fingerprinting method (e.g. JA4, JA3, etc.) to use. This option must be specified.
63+
64+
.. option:: --mode <overwrite|keep|append>
65+
66+
This option specifies what to do if requests from clients have the header names that are specified
67+
by `--header` and/or `--via-header`. Available setting values are "overwrite", "keep" and "append".
68+
The default mode is "overwrite".
69+
70+
.. option:: --servernames <servername1,servername2,...>
71+
72+
This option specifies server name(s) for which the plugin generates fingerprints.
73+
The value must be provided as a single comma separated value (no space) of server names.
74+
If the option is not specified, the plugin generates fingerprints for any server names.
75+
76+
.. option:: --header <header_name>
77+
78+
This option specifies the name of the header field where the plugin stores the generated fingerprint value. If not specified, header generation will be suppressed.
79+
80+
.. option:: --via-header <via_header_name>
81+
82+
This option specifies the name of the header field where the plugin stores the generated fingerprint-via value. If not specified, header generation will be suppressed.
83+
84+
.. option:: --log-filename <filename>
85+
86+
This option specifies the filename for the plugin log file. If not specified, log output will be suppressed.
87+
88+
89+
Plugin Behavior
90+
===============
91+
92+
Global plugin setup
93+
-------------------
94+
95+
Global plugin setup is the best if you:
96+
* Need a fingerprint on every request
97+
98+
Remap plugin setup
99+
------------------
100+
101+
Remap plugin setup is the best if you:
102+
* Need a fingerprint only on specific paths, or
103+
* Cannot use Global plugin setup
104+
105+
.. note:: 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.
106+
107+
Hybrid setup
108+
------------
109+
110+
Hybrid setup is the best if you:
111+
* Need a fingerprint only for specific server names (in TLS SNI extension), and
112+
* Need a fingerprint only on specific paths
113+
114+
115+
Log Output
116+
==========
117+
118+
The plugin outputs a log file in the Traffic Server log directory (typically ``/var/log/trafficserver/``) if a log filename is
119+
specified by ``--log-filename`` option.
120+
121+
**Log Format**::
122+
123+
[timestamp] Client: <address> <method_name>: <fingerprint>
124+
125+
**Example**::
126+
127+
[Jan 29 10:15:23.456] Client: 192.168.1.100 JA4: t13d1516h2_8daaf6152771_b186095e22b6
128+
[Jan 29 10:15:24.123] Client: 10.0.0.50 JA4: t13d1715h2_8daaf6152771_02713d6af862
129+
130+
131+
Using HTTP Headers in Origin Requests
132+
=====================================
133+
134+
Origin servers can access the generated fingerprint through the injected HTTP header.
135+
This allows the origin to:
136+
137+
* Make access control decisions based on client fingerprints
138+
* Log fingerprints for security analysis
139+
* Track client populations and TLS implementation patterns
140+
141+
The fingerprint-via header allows origin servers to track which Traffic Server proxy handled the request when multiple proxies are deployed.
142+
143+
144+
Debugging
145+
=========
146+
147+
To enable debug logging for the plugin, set the following in :file:`records.yaml`::
148+
149+
records:
150+
diags:
151+
debug:
152+
enabled: 1
153+
tags: jax_fingerprint
154+
155+
156+
Requirements
157+
============
158+
159+
* Traffic Server must be built with TLS support (OpenSSL or BoringSSL) if you use JA3 or JA4
160+
161+
162+
See Also
163+
========
164+
* JA3 Technical Specification: https://github.com/FoxIO-LLC/ja3
165+
* JA4+ Technical Specification: https://github.com/FoxIO-LLC/ja4
166+
167+
168+
Example Configuration
169+
=====================
170+
171+
Enable JA4 fingerprinting by hybrid (global + remap) setup
172+
----------------------------------------------------------
173+
174+
This configuration adds x-my-ja4 header if a connection is established for either abc.example or xyz.example.
175+
176+
**plugin.config**::
177+
178+
jax_fingerprint.so --method JA4 --servernames abc.example,xyz.example
179+
180+
**remap.config**::
181+
182+
map / http://origin.example/ @plugin=jax_fingerprint.so @pparam=--method=JA4 @pparam=--header=x-my-ja4

plugins/experimental/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ endif()
6868
if(BUILD_JA4_FINGERPRINT)
6969
add_subdirectory(ja4_fingerprint)
7070
endif()
71+
if(BUILD_JAX_FINGERPRINT)
72+
add_subdirectory(jax_fingerprint)
73+
endif()
7174
if(BUILD_MAGICK)
7275
add_subdirectory(magick)
7376
endif()
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#######################
2+
#
3+
# Licensed to the Apache Software Foundation (ASF) under one or more contributor license
4+
# agreements. See the NOTICE file distributed with this work for additional information regarding
5+
# copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0
6+
# (the "License"); you may not use this file except in compliance with the License. You may obtain
7+
# a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software distributed under the License
12+
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13+
# or implied. See the License for the specific language governing permissions and limitations under
14+
# the License.
15+
#
16+
#######################
17+
18+
add_atsplugin(
19+
jax_fingerprint
20+
plugin.cc
21+
context.cc
22+
userarg.cc
23+
header.cc
24+
log.cc
25+
ja3/ja3_method.cc
26+
ja3/ja3_utils.cc
27+
ja4/ja4_method.cc
28+
ja4/ja4.cc
29+
ja4/tls_client_hello_summary.cc
30+
ja4h/ja4h_method.cc
31+
ja4h/ja4h.cc
32+
ja4h/datasource.cc
33+
)
34+
target_link_libraries(jax_fingerprint PRIVATE OpenSSL::Crypto OpenSSL::SSL)
35+
verify_global_plugin(jax_fingerprint)
36+
target_include_directories(jax_fingerprint BEFORE PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
37+
38+
if(BUILD_TESTING)
39+
add_executable(
40+
test_jax
41+
ja3/test_ja3.cc
42+
ja3/ja3_utils.cc
43+
ja4/test_ja4.cc
44+
ja4/ja4.cc
45+
ja4/tls_client_hello_summary.cc
46+
ja4h/test_ja4h.cc
47+
ja4h/ja4h.cc
48+
ja4h/datasource.cc
49+
)
50+
target_link_libraries(test_jax PRIVATE Catch2::Catch2WithMain OpenSSL::Crypto OpenSSL::SSL)
51+
target_include_directories(test_jax BEFORE PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
52+
53+
add_catch2_test(NAME test_jax COMMAND test_jax)
54+
endif()
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/** @file
2+
3+
@section license License
4+
5+
Licensed to the Apache Software Foundation (ASF) under one
6+
or more contributor license agreements. See the NOTICE file
7+
distributed with this work for additional information
8+
regarding copyright ownership. The ASF licenses this file
9+
to you under the Apache License, Version 2.0 (the
10+
"License"); you may not use this file except in compliance
11+
with the License. You may obtain a copy of the License at
12+
13+
http://www.apache.org/licenses/LICENSE-2.0
14+
15+
Unless required by applicable law or agreed to in writing, software
16+
distributed under the License is distributed on an "AS IS" BASIS,
17+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
See the License for the specific language governing permissions and
19+
limitations under the License.
20+
21+
*/
22+
23+
#pragma once
24+
25+
#include "ts/ts.h"
26+
#include "plugin.h"
27+
#include "method.h"
28+
29+
#include <string>
30+
#include <unordered_set>
31+
32+
enum class Mode : int {
33+
OVERWRITE,
34+
KEEP,
35+
APPEND,
36+
};
37+
38+
enum class PluginType : int {
39+
GLOBAL,
40+
REMAP,
41+
};
42+
43+
// This hash function enables looking up the set by a string_view without making a temporary string object.
44+
struct StringHash {
45+
// Enable heterogeneous lookup
46+
using is_transparent = void;
47+
48+
size_t
49+
operator()(std::string_view sv) const
50+
{
51+
return std::hash<std::string_view>{}(sv);
52+
}
53+
};
54+
55+
struct PluginConfig {
56+
PluginConfig() { Dbg(dbg_ctl, "New config (%p) has been created", this); }
57+
~PluginConfig() { Dbg(dbg_ctl, "Config for (%p) has been deleted", this); }
58+
59+
PluginType plugin_type = PluginType::GLOBAL;
60+
Mode mode = Mode::OVERWRITE;
61+
struct Method method = {"uninitialized", Method::Type::CONNECTION_BASED, nullptr, nullptr};
62+
std::string header_name = "";
63+
std::string via_header_name = "";
64+
std::string log_filename = "";
65+
int user_arg_index = -1;
66+
TSCont handler = nullptr; // For remap plugin
67+
bool standalone = false;
68+
std::unordered_set<std::string, StringHash, std::equal_to<>> servernames;
69+
TSTextLogObject log_handle = nullptr;
70+
};

0 commit comments

Comments
 (0)