Hi everyone,
I am deploying Suricata (8.0.5) in a topology where an upstream SSL proxy handles TLS termination/decryption before passing the plaintext traffic to Suricata.
Suricata Dataset would be used to support big list of malicious ja4 fingerprints.
Because Suricata only receives the decrypted packets, it does not see the original TLS handshake packets (Client Hello). Consequently, Suricata cannot natively calculate the JA4 fingerprint for these sessions.
The upstream SSL proxy is capable of calculating the JA4 fingerprint during the initial handshake.
My question: Is there an existing, standard way to pass this externally calculated JA4 fingerprint from the proxy to Suricata so that Suricata can perform a lookup against a configured dataset?
A few specific points I am trying to figure out:
- Transmission Mechanism: Can Suricata accept this metadata via a custom protocol header (e.g., encapsulating the decrypted traffic in Geneve, GRE, or a custom HTTP header) and parse it into a usable variable?
- Rule Syntax / Engine Interaction: Once passed, how can we reference this external fingerprint in a Suricata signature to trigger a dataset match (e.g., matching a
ja4.hash equivalent against a blocklist)?
- Another approach, can we register a function to trigger the ja4 lookup after setting the ja4 fingerprint with the suricata as part of the flow . and suricata can perform the lookup against the dataset.
- Alternative Architecture: If this is not natively supported, what is the recommended best practice for this architecture? (e.g., sending a duplicate stream of the raw encrypted handshake traffic to a separate Suricata interface just for JA4 logging/matching?
Any insights, workarounds, or pointers to relevant documentation/plugins would be greatly appreciated!
Thanks!
I think SSL inspection is content inspection. So I don’t have any answers to your question.
But I’d like to understand your use case. Because I am not sure how successful a JA4 based shallow inspection would be (especially on a middle box):
- Cleartext ClientHello is fakeable, and its JA4 is prone to false positives/negatives. (This depends on the sophistication of the attacker or the tool used.)
- ClientHelloInner in ECH is not fakeable, as it is encrypted, but an SSL proxy cannot generate its JA4. (But edge servers can.)
Then again, I know that many system/network admins use JA4 for shallow inspection, not for blocking connections directly, but for filtering in the first layer of defense, right?
Can you tell me more about your use case involving an SSL proxy, and why? What am I missing here?
Topology & Architecture:
TLS Traffic → SSL Proxy → Decrypted Traffic -> Suricata Engine
Use Case:
We receive a large list of malicious JA4 fingerprint hashes from an external threat intelligence vendor, which we load into Suricata using Datasets. We want to enforce an automated drop/block action when a connection matches a malicious JA4 fingerprint.
The Challenge:
Because our SSL Proxy terminates and decrypts the TLS connection before forwarding the plain text to Suricata, Suricata never sees the original TLS handshake packets (ClientHello). As a result, Suricata cannot calculate the JA4 fingerprint natively on the decrypted stream.
Proposed Approaches:
Since the SSL Proxy handles the TLS handshake, it calculates the JA4 fingerprint directly. We are evaluating the best way to pass this metadata to Suricata for rule matching:
-
Custom HTTP Header: The proxy injects a custom HTTP header (e.g., X-JA4-Fingerprint: <hash>) into the decrypted HTTP request before forwarding it to Suricata. Suricata can then evaluate this header against our JA4 dataset using http.header.
-
Alternative Metadata Mechanisms: Exploring whether custom headers are the optimal approach, or if alternatives like PROXY Protocol v2 (custom TLVs) or socket-based feeds are better suited—especially for non-HTTP TLS traffic.
Questions
-
Is injecting a custom HTTP header the recommended standard for passing proxy-calculated JA4 fingerprints to Suricata?
-
How are others handling JA4 enforcement in environments where inline SSL proxy decryption takes place upstream of Suricata?
-
For non-HTTP TLS traffic, what is the best mechanism to relay proxy-calculated JA4 metadata to Suricata for dataset matching?.
If I try to implement JA4 support in my ICAP architecture for SSLproxy and icapsuricata, I would compute it in SSLproxy and pass it to icapsuricata in a custom X-header. And then icapsuricata could inject that JA4 info in the emulated packets it injects into libsuricata. For example, in line with your proposed approaches:
-
icapsuricata could use the same X-header for JA4 in the emulated packets injected into libsuricata, but this would work with HTTP traffic only.
-
icapsuricata could inject JA4 in a custom TCP extension, as it does with the TCP Option 78 to pass the actual src port to libsuricata.
So far is possible. But, the crucial missing part here (which is at the center of your questions) is whether Suricata can use the JA4 info passed to it by those proposed approaches, instead of trying to compute it itself. I’m not a Suricata developer, but I don’t think so, and I am not aware of any API function to pass JA4 or ClientHello to libsuricata either (I hope I am wrong).
In summary, until such a feature to use externally supplied JA4 is implemented in Suricata, the only way at the moment seems to feed the original encrypted traffic to Suricata (the option 4 in your list).
Btw, IMHO, I still don’t think JA4 should be used to “enforce an automated drop/block action” as you aim for, due to the reasons I mentioned in my previous answer.