-
Notifications
You must be signed in to change notification settings - Fork 851
Add BoringSSL support to the ja4_fingerprint plugin #12914
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
d2c0e22
got client hello routed to plugins
jasmine-nahrain 5538496
Creates ja4 fingerprint with boringssl
jasmine-nahrain 2c6a0d0
cleanup a bit
jasmine-nahrain 2dff963
make ssl_client_hello const
jasmine-nahrain fec3cee
spaces cleanup
jasmine-nahrain 5620920
cleanup code
jasmine-nahrain 7664657
more cleanup
jasmine-nahrain e42e776
Update plugin.cc
jasmine-nahrain 08168c7
Update plugin.cc
jasmine-nahrain 23fe047
Update ts.h
jasmine-nahrain 7ee0bcf
Update apidefs.h.in
jasmine-nahrain 70a568f
Update to make more clean
jasmine-nahrain 333d697
Update data
jasmine-nahrain 576fa4f
address comments
jasmine-nahrain 360526f
Update ja4_fingerprint.en.rst
jasmine-nahrain 30db0c3
Add docs
jasmine-nahrain 432e4ba
Update TSVConnClientHelloGet.en.rst
jasmine-nahrain 74510d9
Update TSVConnClientHelloGet.en.rst
jasmine-nahrain 5629d59
Address comments
jasmine-nahrain d76df15
Update TSClientHello.en.rst
jasmine-nahrain c8d37e0
Update TSClientHello.en.rst
jasmine-nahrain 293f873
Eliminate heap allocations
maskit 9c6174e
Address Copilot comments
maskit 5ad1745
Address Copilot comments
maskit a87095b
Update doxygen comments
maskit File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,209 @@ | ||
| .. Licensed to the Apache Software Foundation (ASF) under one | ||
| or more contributor license agreements. See the NOTICE file | ||
| distributed with this work for additional information | ||
| regarding copyright ownership. The ASF licenses this file | ||
| to you under the Apache License, Version 2.0 (the | ||
| "License"); you may not use this file except in compliance | ||
| with the License. You may obtain a copy of the License at | ||
|
|
||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
|
|
||
| Unless required by applicable law or agreed to in writing, | ||
| software distributed under the License is distributed on an | ||
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| KIND, either express or implied. See the License for the | ||
| specific language governing permissions and limitations | ||
| under the License. | ||
|
|
||
| .. include:: ../../common.defs | ||
|
|
||
| .. _admin-plugins-ja4-fingerprint: | ||
|
|
||
| JA4 Fingerprint Plugin | ||
| ********************** | ||
|
|
||
| Description | ||
| =========== | ||
|
|
||
| The JA4 Fingerprint plugin generates TLS client fingerprints based on the JA4 | ||
| algorithm designed by John Althouse. JA4 is the successor to the JA3 | ||
| fingerprinting algorithm and provides improved client identification for TLS | ||
| connections. | ||
|
|
||
| A JA4 fingerprint uniquely identifies TLS clients based on characteristics of | ||
| their TLS ClientHello messages, including: | ||
|
|
||
| * TLS version | ||
| * ALPN (Application-Layer Protocol Negotiation) preferences | ||
| * Cipher suites offered | ||
| * TLS extensions present | ||
|
|
||
| This information can be used for: | ||
|
|
||
| * Client identification and tracking | ||
| * Bot detection and mitigation | ||
| * Security analytics and threat intelligence | ||
| * Understanding client TLS implementation patterns | ||
|
|
||
| How It Works | ||
| ============ | ||
|
|
||
| The plugin intercepts TLS ClientHello messages during the TLS handshake and | ||
| generates a JA4 fingerprint consisting of three sections separated by underscores: | ||
|
|
||
| **Section a (unhashed)**: Basic information about the client including: | ||
|
|
||
| * Protocol (``t`` for TCP, ``q`` for QUIC) | ||
| * TLS version | ||
| * SNI (Server Name Indication) status | ||
| * Number of cipher suites | ||
| * Number of extensions | ||
| * First ALPN value | ||
|
|
||
| **Section b (hashed)**: A SHA-256 hash of the sorted cipher suite list | ||
|
|
||
| **Section c (hashed)**: A SHA-256 hash of the sorted extension list | ||
|
|
||
| Example fingerprint:: | ||
|
|
||
| t13d1516h2_8daaf6152771_b186095e22b6 | ||
|
|
||
| Key Differences from JA3 | ||
| ------------------------- | ||
|
|
||
| * Cipher suites and extensions are sorted before hashing for consistency | ||
| * SNI and ALPN information is included in the fingerprint | ||
| * More resistant to fingerprint randomization | ||
|
|
||
| Plugin Configuration | ||
| ==================== | ||
|
|
||
| The plugin operates as a global plugin and has no configuration options. | ||
|
|
||
| To enable the plugin, add the following line to :file:`plugin.config`:: | ||
|
|
||
| ja4_fingerprint.so | ||
|
|
||
| No additional parameters are required or supported. | ||
|
|
||
| Plugin Behavior | ||
| =============== | ||
|
|
||
| When loaded, the plugin will: | ||
|
|
||
| 1. **Capture TLS ClientHello**: Intercepts all incoming TLS connections during | ||
| the ClientHello phase | ||
|
|
||
| 2. **Generate Fingerprint**: Calculates the JA4 fingerprint from the | ||
| ClientHello data | ||
|
|
||
| 3. **Log to File**: Writes the fingerprint and client IP address to | ||
| ``ja4_fingerprint.log`` | ||
|
|
||
| 4. **Add HTTP Headers**: Injects the following headers into subsequent HTTP | ||
| requests on the same connection: | ||
|
|
||
| * ``ja4``: Contains the JA4 fingerprint | ||
| * ``x-ja4-via``: Contains the proxy name (from ``proxy.config.proxy_name``) | ||
|
|
||
| Log Output | ||
| ========== | ||
|
|
||
| The plugin writes to ``ja4_fingerprint.log`` in the Traffic Server log | ||
| directory (typically ``/var/log/trafficserver/``). | ||
|
|
||
| **Log Format**:: | ||
|
|
||
| [timestamp] Client IP: <ip_address> JA4: <fingerprint> | ||
|
|
||
| **Example**:: | ||
|
|
||
| [Jan 29 10:15:23.456] Client IP: 192.168.1.100 JA4: t13d1516h2_8daaf6152771_b186095e22b6 | ||
| [Jan 29 10:15:24.123] Client IP: 10.0.0.50 JA4: t13d1715h2_8daaf6152771_02713d6af862 | ||
|
|
||
| Using JA4 Headers in Origin Requests | ||
| ===================================== | ||
|
|
||
| Origin servers can access the JA4 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 ``x-ja4-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 :file:`records.yaml`:: | ||
|
|
||
| records: | ||
| diags: | ||
| debug: | ||
| enabled: 1 | ||
| tags: ja4_fingerprint | ||
|
|
||
| Debug output will appear in :file:`diags.log` and includes: | ||
|
|
||
| * ClientHello processing events | ||
| * Fingerprint generation details | ||
| * Header injection operations | ||
|
|
||
| Requirements | ||
| ============ | ||
|
|
||
| * Traffic Server must be built with TLS support (OpenSSL or BoringSSL) | ||
| * The plugin operates on all TLS connections | ||
|
|
||
| Configuration Settings | ||
| ====================== | ||
|
|
||
| The plugin requires the ``proxy.config.proxy_name`` setting to be configured | ||
| for the ``x-ja4-via`` header. If not set, the plugin will log an error and use | ||
| "unknown" as the proxy name. | ||
|
|
||
| To set the proxy name in :file:`records.yaml`:: | ||
|
|
||
| records: | ||
| proxy: | ||
| config: | ||
| proxy_name: proxy01 | ||
|
|
||
| Limitations | ||
| =========== | ||
|
|
||
| * The plugin only operates in global mode (no per-remap configuration) | ||
| * Logging cannot be disabled | ||
| * Raw (unhashed) cipher and extension lists are not logged | ||
| * Non-TLS connections do not generate fingerprints | ||
|
|
||
| See Also | ||
| ======== | ||
|
|
||
| * JA4 Technical Specification: https://github.com/FoxIO-LLC/ja4/blob/main/technical_details/JA4.md | ||
| * JA4 is licensed under the BSD 3-Clause license | ||
|
|
||
| Example Configuration | ||
| ===================== | ||
|
|
||
| Complete example configuration for enabling JA4 fingerprinting: | ||
|
|
||
| **plugin.config**:: | ||
|
|
||
| ja4_fingerprint.so | ||
|
|
||
| **records.yaml**:: | ||
|
|
||
| records: | ||
| proxy: | ||
| config: | ||
| proxy_name: proxy-01 | ||
| diags: | ||
| debug: | ||
| enabled: 1 | ||
| tags: ja4_fingerprint | ||
|
|
||
| After restarting Traffic Server, the plugin will begin fingerprinting TLS | ||
| connections and logging to ``ja4_fingerprint.log``. |
50 changes: 50 additions & 0 deletions
50
doc/developer-guide/api/functions/TSVConnClientHelloGet.en.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| .. Licensed to the Apache Software Foundation (ASF) under one or more | ||
| contributor license agreements. See the NOTICE file distributed | ||
| with this work for additional information regarding copyright | ||
| ownership. The ASF licenses this file to you under the Apache | ||
| License, Version 2.0 (the "License"); you may not use this file | ||
| except in compliance with the License. You may obtain a copy of | ||
| the License at | ||
|
|
||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
|
|
||
| Unless required by applicable law or agreed to in writing, software | ||
| distributed under the License is distributed on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||
| implied. See the License for the specific language governing | ||
| permissions and limitations under the License. | ||
|
|
||
| .. include:: ../../../common.defs | ||
|
|
||
| .. default-domain:: cpp | ||
|
|
||
| TSVConnClientHelloGet | ||
| ********************* | ||
|
|
||
| Synopsis | ||
| ======== | ||
|
|
||
| .. code-block:: cpp | ||
|
|
||
| #include <ts/ts.h> | ||
|
|
||
| .. function:: TSClientHello TSVConnClientHelloGet(TSVConn sslp) | ||
| .. function:: TSReturnCode TSClientHelloExtensionGet(TSClientHello ch, unsigned int type, const unsigned char **out, size_t *outlen) | ||
|
|
||
| Description | ||
| =========== | ||
|
|
||
| :func:`TSVConnClientHelloGet` retrieves ClientHello message data from the TLS | ||
| virtual connection :arg:`sslp`. Returns a :type:`TSClientHello` always. The availability | ||
| of the returned object must be checked before use. | ||
|
|
||
| .. important:: | ||
|
|
||
| This function should only be called from the ``TS_EVENT_SSL_CLIENT_HELLO`` hook. | ||
| The returned :type:`TSClientHello` is only valid during the SSL ClientHello event processing. | ||
| Using this function from other hooks may result in accessing invalid or stale data. | ||
|
|
||
| :func:`TSClientHelloExtensionGet` retrieves extension data for the specified | ||
| :arg:`type` (e.g., ``0x10`` for ALPN). Returns :enumerator:`TS_SUCCESS` if | ||
| found, :enumerator:`TS_ERROR` otherwise. The returned pointer in :arg:`out` is | ||
| valid only while :arg:`ch` exists. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| .. Licensed to the Apache Software Foundation (ASF) under one or more | ||
| contributor license agreements. See the NOTICE file distributed | ||
| with this work for additional information regarding copyright | ||
| ownership. The ASF licenses this file to you under the Apache | ||
| License, Version 2.0 (the "License"); you may not use this file | ||
| except in compliance with the License. You may obtain a copy of | ||
| the License at | ||
|
|
||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
|
|
||
| Unless required by applicable law or agreed to in writing, software | ||
| distributed under the License is distributed on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||
| implied. See the License for the specific language governing | ||
| permissions and limitations under the License. | ||
|
|
||
| .. include:: ../../../common.defs | ||
|
|
||
| .. default-domain:: cpp | ||
|
|
||
| TSClientHello | ||
| ************* | ||
|
|
||
| Synopsis | ||
| ======== | ||
|
|
||
| .. code-block:: cpp | ||
|
|
||
| #include <ts/apidefs.h> | ||
|
|
||
| .. type:: TSClientHello | ||
|
|
||
| .. type:: TSClientHello::TSExtensionTypeList | ||
|
|
||
| A type alias for an iterable container of extension type IDs. | ||
|
|
||
|
|
||
| Description | ||
| =========== | ||
|
|
||
| :type:`TSClientHello` is an opaque handle to a TLS ClientHello message sent by | ||
| a client during the TLS handshake. It provides access to the client's TLS | ||
| version, cipher suites, and extensions. | ||
|
|
||
| The implementation abstracts differences between OpenSSL and BoringSSL to | ||
| provide a consistent interface. | ||
|
|
||
| Accessor Methods | ||
| ================ | ||
|
|
||
| The following methods are available to access ClientHello data: | ||
|
|
||
| .. function:: bool is_available() const | ||
|
|
||
| Returns whether the object contains valid values. As long as | ||
| :func:`TSVConnClientHelloGet` is called for a TLS connection, the return | ||
| value should be `true`. | ||
|
|
||
| .. function:: uint16_t get_version() const | ||
|
|
||
| Returns the TLS version from the ClientHello message. | ||
|
|
||
| .. function:: const uint8_t* get_cipher_suites() const | ||
|
|
||
| Returns a pointer to the cipher suites buffer. The length is available via | ||
| :func:`get_cipher_suites_len()`. | ||
|
|
||
| .. function:: size_t get_cipher_suites_len() const | ||
|
|
||
| Returns the length of the cipher suites buffer in bytes. | ||
|
|
||
| .. function:: TSClientHello::TSExtensionTypeList get_extension_types() const | ||
|
|
||
| Returns an iterable container of extension type IDs present in the ClientHello. | ||
| This method abstracts the differences between BoringSSL (which uses an extensions | ||
| buffer) and OpenSSL (which uses an extension_ids array), providing a consistent | ||
| interface regardless of the SSL library in use. | ||
|
|
||
| .. function:: void* _get_internal() const | ||
|
|
||
| Returns a pointer to internal implementation data. This is an internal accessor for advanced use | ||
| cases. This accessor is not part of the stable public API, and plugins must not cast or rely | ||
| on the returned pointer type. |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.