nginx-ssl-fingerprint icon indicating copy to clipboard operation
nginx-ssl-fingerprint copied to clipboard

high performance ja3 and http2 fingerprint for nginx.

nginx-ssl-fingerprint

A stable nginx module for SSL/TLS ja3 fingerprint, with high performance.

Patches

  • nginx - save client hello fingerprint
  • openssl - expose client hello data

Configuration

Variables

Name Default Value Comments
http_ssl_greased 0 Chrome grease flag
http_ssl_ja3 NULL The ja3 fingerprint for a SSL connection for a HTTP server.
http_ssl_ja3_hash NULL ja3 md5 hash

Example

http {
    server {
        listen                 127.0.0.1:8443 ssl;
        ssl_certificate        cert.pem;
        ssl_certificate_key    priv.key;
        error_log              /dev/stderr debug;
        return                 200 "$http_ssl_ja3";
    }
}

Quick Start


# Clone

$ git clone -b OpenSSL_1_1_1-stable --depth=1 https://github.com/openssl/openssl
$ git clone -b release-1.23.1 --depth=1 https://github.com/nginx/nginx
$ git clone https://github.com/phuslu/nginx-ssl-fingerprint

# Patch

$ patch -p1 -d openssl < nginx-ssl-fingerprint/patches/openssl.1_1_1.patch
$ patch -p1 -d nginx < nginx-ssl-fingerprint/patches/nginx.patch

# Configure & Build

$ cd nginx
$ ASAN_OPTIONS=symbolize=1 ./auto/configure --with-openssl=$(pwd)/../openssl --add-module=$(pwd)/../nginx-ssl-fingerprint --with-http_ssl_module --with-stream_ssl_module --with-debug --with-stream --with-cc-opt="-fsanitize=address -O -fno-omit-frame-pointer" --with-ld-opt="-L/usr/local/lib -Wl,-E -lasan"
$ make

# Test

$ objs/nginx -p . -c $(pwd)/../nginx-ssl-fingerprint/nginx.conf
$ curl -k https://127.0.0.1:8444

Performance

Server

Type Service Cores Memeory(G)
Server nginx with 5 worker 8 8
Client wrk 8 8

Performance Results

for i in $(seq 1 10); do
    wrk https://localhost/  --latency -t48 -d15 -c2000  >/tmp/wrk.log.$i
done
  • QPS: Average Req/Second in 10 times
  • Latency: Average 50% latency (ms) in 10 times

v0.2.0 ~ v0.3.0

WRK Connection QPS Cost Origin Req/Sec Origin Latency Req/Sec with fingerprint Latency with fingerprint
50 9.98% 2990.26 14.151 2694.96 15.957
100 26.2% 3718.62 24.397 2743.47 32.091
200 20.1% 3680.09 49.332 2941.92 63.351
500 27.1% 3503.64 111.085 2555.59 149.989
1000 22.4% 3333.68 134.187 2586.89 169.36
1500 28.6% 3497.15 135.949 2498.74 177.784
2000 37.0% 2390.82 229.657 1506.78 275.601

v0.4.0

WRK Connection QPS Cost Origin Req/Sec Origin Latency Req/Sec with fingerprint Latency with fingerprint
50 8.60% 36795.9 1.211 33624.2 1.33
100 8.4% 36831.2 2.43545 33734.6 66.8545
200 8.39% 36862.5 4.814 33767.2 5.28
500 8.45 36598.8 11.827 33505.5 12.786
1000 9.63% 33657.1 20.877 36900.1 20.059
1500 8.95% 36806.3 27.591 33511 28.155
2000 8.71% 37460.2 30.664 34194.7 31.504

TLS Client Hello Packet

Frame 103: 561 bytes on wire (4488 bits), 561 bytes captured (4488 bits) on interface utun7, id 0
Null/Loopback
Internet Protocol Version 4, Src: 10.22.76.29, Dst: 143.92.64.129
Transmission Control Protocol, Src Port: 56795, Dst Port: 443, Seq: 1, Ack: 1, Len: 517
    Source Port: 56795
    Destination Port: 443
    [Stream index: 8]
    [Conversation completeness: Complete, WITH_DATA (31)]
    [TCP Segment Len: 517]
    Sequence Number: 1    (relative sequence number)
    Sequence Number (raw): 4163556192
    [Next Sequence Number: 518    (relative sequence number)]
    Acknowledgment Number: 1    (relative ack number)
    Acknowledgment number (raw): 1321024790
    0101 .... = Header Length: 20 bytes (5)
    Flags: 0x018 (PSH, ACK)
    Window: 4096
    [Calculated window size: 262144]
    [Window size scaling factor: 64]
    Checksum: 0xc517 [unverified]
    [Checksum Status: Unverified]
    Urgent Pointer: 0
    [Timestamps]
    [SEQ/ACK analysis]
    TCP payload (517 bytes)
Transport Layer Security
    TLSv1.3 Record Layer: Handshake Protocol: Client Hello
        Content Type: Handshake (22)
        Version: TLS 1.0 (0x0301)
        Length: 512
        Handshake Protocol: Client Hello
            Handshake Type: Client Hello (1)
            Length: 508
            Version: TLS 1.2 (0x0303)
            Random: cba554e69ef810c86d3e843f137dc3759fed3f0d6c621f1fb45acb7f92560b48
            Session ID Length: 32
            Session ID: b0a3a558861404d133bc11f9d6b4a4b32b60caaa1559e9332165dc2ac1643d28
            Cipher Suites Length: 32
            Cipher Suites (16 suites)
                Cipher Suite: Reserved (GREASE) (0x6a6a)
                Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301)
                Cipher Suite: TLS_AES_256_GCM_SHA384 (0x1302)
                Cipher Suite: TLS_CHACHA20_POLY1305_SHA256 (0x1303)
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca9)
                Cipher Suite: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8)
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)
                Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c)
                Cipher Suite: TLS_RSA_WITH_AES_256_GCM_SHA384 (0x009d)
                Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f)
                Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035)
            Compression Methods Length: 1
            Compression Methods (1 method)
                Compression Method: null (0)
            Extensions Length: 403
            Extension: Reserved (GREASE) (len=0)
                Type: Reserved (GREASE) (27242)
                Length: 0
                Data: <MISSING>
            Extension: server_name (len=29)
                Type: server_name (0)
                Length: 29
                Server Name Indication extension
            Extension: extended_master_secret (len=0)
                Type: extended_master_secret (23)
                Length: 0
            Extension: renegotiation_info (len=1)
                Type: renegotiation_info (65281)
                Length: 1
                Renegotiation Info extension
            Extension: supported_groups (len=10)
                Type: supported_groups (10)
                Length: 10
                Supported Groups List Length: 8
                Supported Groups (4 groups)
            Extension: ec_point_formats (len=2)
                Type: ec_point_formats (11)
                Length: 2
                EC point formats Length: 1
                Elliptic curves point formats (1)
            Extension: session_ticket (len=0)
                Type: session_ticket (35)
                Length: 0
                Data (0 bytes)
            Extension: application_layer_protocol_negotiation (len=14)
                Type: application_layer_protocol_negotiation (16)
                Length: 14
                ALPN Extension Length: 12
                ALPN Protocol
            Extension: status_request (len=5)
                Type: status_request (5)
                Length: 5
                Certificate Status Type: OCSP (1)
                Responder ID list Length: 0
                Request Extensions Length: 0
            Extension: signature_algorithms (len=18)
                Type: signature_algorithms (13)
                Length: 18
                Signature Hash Algorithms Length: 16
                Signature Hash Algorithms (8 algorithms)
            Extension: signed_certificate_timestamp (len=0)
                Type: signed_certificate_timestamp (18)
                Length: 0
            Extension: key_share (len=43)
                Type: key_share (51)
                Length: 43
                Key Share extension
            Extension: psk_key_exchange_modes (len=2)
                Type: psk_key_exchange_modes (45)
                Length: 2
                PSK Key Exchange Modes Length: 1
                PSK Key Exchange Mode: PSK with (EC)DHE key establishment (psk_dhe_ke) (1)
            Extension: supported_versions (len=7)
                Type: supported_versions (43)
                Length: 7
                Supported Versions length: 6
                Supported Version: Reserved (GREASE) (0x7a7a)
                Supported Version: TLS 1.3 (0x0304)
                Supported Version: TLS 1.2 (0x0303)
            Extension: compress_certificate (len=3)
                Type: compress_certificate (27)
                Length: 3
                Algorithms Length: 2
                Algorithm: brotli (2)
            Extension: application_settings (len=5)
                Type: application_settings (17513)
                Length: 5
                ALPS Extension Length: 3
                Supported ALPN List
                    Supported ALPN Length: 2
                    Supported ALPN: h2
            Extension: Reserved (GREASE) (len=1)
                Type: Reserved (GREASE) (64250)
                Length: 1
                Data: 00
            Extension: padding (len=191)
                Type: padding (21)
                Length: 191
                Padding Data: 000000000000000000000000000000000000000000000000000000000000000000000000…
            [JA3 Fullstring: 771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513-21,29-23-24,0]
            [JA3: cd08e31494f9531f560d64c695473da9]

Ja3

As we know that, we canJA3 is a method for creating SSL/TLS client fingerprints that should be easy to produce on any platform and can be easily shared for threat intelligence.

This module adds new nginx variables for the SSL/TLS ja3 fingerprint. For more information, please see the salesforce ja3

JA3 take 5 fields from TLS Client Hello packet (example client-hello), each filed convert to decimal and join by '-', then the 5 fields string join by  ','   and then get the ja3 full string.

The ja3 full string's length is not fixed, it's hard to compare. So finally hash the ja3 full string to md5 for easy store or compare.

One Ja3 full string contains 5 parts:

  • TLSVersion: convert the hex to decimal
  • Ciphers: convert the hex to decimal and join by '-'
  • Extensions: use type value and join by '-' (it's decimal, no need to convert)
  • Supported Groups/Elliptic_Curves: convert hex to decimal and join by '-' (exclude Reserved GREASE )
  • EC_Point_Formats: always be 0 or empty (needs to confirm more details)

Field 1 - TLSVersion

• TLS Record - Version: minimum supported TLS version (in TLS 1.2 and before). In TLS 1.3, this field is not really used and MUST be 0x0303 ("TLS 1.2") or 0x301 ("TLS 1.0") for compatibility purposes. Reference: RFC 8446 (page 79)

• Client Hello - Version: maximum supported TLS version (in TLS 1.2 and before). In TLS 1.3, this field is not used but MUST be set to 0x0303 ("TLS 1.2"). Reference: RFC 8446 (4.1.2. Client Hello)

Currently, the nginx-ssl-fingerprint used nginx connection, it means the tls version is negotiated.

We are trying to use another TLSVersion which donot take affect by server side.

Filed 2 - Ciphers

The filed does not special. For the new OpenSSL lib, the support ciphers count can reach 30 or higher, such as curl.

Filed 3 - Extensions

The extensions order is random, but relay on the OpenSSL library.  Every tool has its own SSL lib, so even if restarting the devices, the TLS fingerprint does not change.

OpenSSL ID Extension name Remark
0 TLSEXT_TYPE_server_name
5 TLSEXT_TYPE_status_request patched after v0.3.0
10 TLSEXT_TYPE_supported_groups
11 TLSEXT_TYPE_ec_point_formats
13 TLSEXT_TYPE_signature_algorithms
16 TLSEXT_TYPE_application_layer_protocol_negotiation
18 TLSEXT_TYPE_signed_certificate_timestamp
21 TLSEXT_TYPE_padding
23 TLSEXT_TYPE_extended_master_secret
27 TLSEXT_TYPE_compress_certificate patched
28 TLSEXT_TYPE_record_size_limit pathed
35 TLSEXT_TYPE_session_ticket
43 TLSEXT_TYPE_supported_versions
45 TLSEXT_TYPE_psk_kex_modes
51 TLSEXT_TYPE_key_share
17513 TLSEXT_TYPE_application_settings patched after v0.3.0
0xff01 TLSEXT_TYPE_renegotiate
- Reserved

TLSEXT_TYPE_supported_groups and TLSEXT_TYPE_elliptic_curves they are same filed. More details refer: https://github.com/openssl/openssl/blob/master/include/openssl/tls1.h#L102-L103

Filed 4 - EllipticCurves

The filed use extensions TLSEXT_TYPE_supported_groups(TLSEXT_TYPE_elliptic_curves) supported group value, and convert to integer.

Filed 5 - EllipticCurvePointFormats

The filed use extensions TLSEXT_TYPE_ec_point_formats value, and convert to int.