Releases: wi1dcard/fingerproxy
v1.1.1
v1.1.0
This release contains one new feature and one bugfix.
Fixed number of cipher suites and extensions in JA4
TLS certificates hot-reloading
Fingerproxy now watches TLS certificate files. Certificate will be hot-reloaded when the files change. This is useful on production environments where certificates might get renewed while fingerproxy runs for months.
Change log
48f9e55 (HEAD, tag: v1.1.0, origin/master) Watch TLS cert file changes to update certs when needed. (#20)
cb0ae8e Fix JA4 number of cipher suites and extensions (#19)
v1.0.1
v1.0.0
v0.6.1
v0.6.0
This release mainly improved the example echo-server. Thanks to @hellodword's idea and help.
Refactored Echo Server
The echo-server has been totally refactored in this release, added a new API /json/detail
.
Just like wwhtrbbtt/TrackMe, /json/detail
prints all raw info captured by fingerproxy, as well as the human-readable, parsed TLS cipher suites, extensions, etc. This helps debug and investigate.
Here is an example usage:
# download and start echo server
./echo-server_linux_amd64 -verbose
# in another terminal
curl https://localhost:8443/json/detail --insecure --http2 | jq
Example output (click to open)
{
"detail": {
"metadata": {
"ClientHelloRecord": "FgMBAgABAAH8AwNlhx0inELmjHnGk5KYmt+kigFGk2b2xNjYo7AyU6dTlyBgdna7azCBa6kK22fUTW3DodYTAz4QHJwueJDe+1GCKAA+EwITAxMBwCzAMACfzKnMqMyqwCvALwCewCTAKABrwCPAJwBnwArAFAA5wAnAEwAzAJ0AnAA9ADwANQAvAP8BAAF1AAAADgAMAAAJbG9jYWxob3N0AAsABAMAAQIACgAWABQAHQAXAB4AGQAYAQABAQECAQMBBAAQAA4ADAJoMghodHRwLzEuMQAWAAAAFwAAADEAAAANADAALgQDBQMGAwgHCAgIGggbCBwICQgKCAsIBAgFCAYEAQUBBgEDAwMBAwIEAgUCBgIAKwAFBAMEAwMALQACAQEAMwAmACQAHQAgT3KA46yLJAIAA2p/Tr1yBq4o+qs5Zc07oIPCwyLJcA0AFQCyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
"ConnectionState": {
"Version": 772,
"HandshakeComplete": true,
"DidResume": false,
"CipherSuite": 4865,
"NegotiatedProtocol": "h2",
"NegotiatedProtocolIsMutual": true,
"ServerName": "localhost",
"PeerCertificates": null,
"VerifiedChains": null,
"SignedCertificateTimestamps": null,
"OCSPResponse": null,
"TLSUnique": null
},
"HTTP2Frames": {
"Settings": [
{
"Id": 3,
"Val": 100
},
{
"Id": 4,
"Val": 10485760
},
{
"Id": 2,
"Val": 0
}
],
"WindowUpdateIncrement": 1048510465,
"Priorities": null,
"Headers": [
{
"Name": ":method",
"Value": "GET",
"Sensitive": false
},
{
"Name": ":scheme",
"Value": "https",
"Sensitive": false
},
{
"Name": ":authority",
"Value": "localhost:8443",
"Sensitive": false
},
{
"Name": ":path",
"Value": "/json/detail",
"Sensitive": false
},
{
"Name": "user-agent",
"Value": "curl/8.6.0",
"Sensitive": false
},
{
"Name": "accept",
"Value": "*/*",
"Sensitive": false
}
]
}
},
"user_agent": "curl/8.6.0",
"ja3": {
"Type": 22,
"Version": 769,
"MessageLen": 0,
"HandshakeType": 1,
"HandshakeLen": 0,
"HandshakeVersion": 771,
"SessionIDLen": 32,
"CipherSuiteLen": 62,
"CipherSuites": [
4866,
4867,
4865,
49196,
49200,
159,
52393,
52392,
52394,
49195,
49199,
158,
49188,
49192,
107,
49187,
49191,
103,
49162,
49172,
57,
49161,
49171,
51,
157,
156,
61,
60,
53,
47,
255
],
"ExtensionLen": 373,
"SNI": "localhost",
"SupportedGroups": [
29,
23,
30,
25,
24,
256,
257,
258,
259,
260
],
"SupportedPoints": "AAEC",
"AllExtensions": [
0,
11,
10,
16,
22,
23,
49,
13,
43,
45,
51,
21
],
"ReadableCipherSuites": [
"TLS_AES_256_GCM_SHA384 (0x1302)",
"TLS_CHACHA20_POLY1305_SHA256 (0x1303)",
"TLS_AES_128_GCM_SHA256 (0x1301)",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)",
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x9f)",
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca9)",
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8)",
"TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xccaa)",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)",
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x9e)",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 (0xc024)",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (0xc028)",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (0x6b)",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 (0xc023)",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (0xc027)",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (0x67)",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x39)",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009)",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x33)",
"TLS_RSA_WITH_AES_256_GCM_SHA384 (0x9d)",
"TLS_RSA_WITH_AES_128_GCM_SHA256 (0x9c)",
"TLS_RSA_WITH_AES_256_CBC_SHA256 (0x3d)",
"TLS_RSA_WITH_AES_128_CBC_SHA256 (0x3c)",
"TLS_RSA_WITH_AES_256_CBC_SHA (0x35)",
"TLS_RSA_WITH_AES_128_CBC_SHA (0x2f)",
"TLS_EMPTY_RENEGOTIATION_INFO_SCSV (0xff)"
],
"ReadableAllExtensions": [
"server_name (0x0)",
"ec_point_formats (0xb)",
"supported_groups (0xa)",
"application_layer_protocol_negotiation (0x10)",
"encrypt_then_mac (0x16)",
"extended_master_secret (0x17)",
"post_handshake_auth (0x31)",
"signature_algorithms (0xd)",
"supported_versions (0x2b)",
"psk_key_exchange_modes (0x2d)",
"key_share (0x33)",
"padding (0x15)"
],
"ReadableSupportedGroups": [
"x25519 (0x1d)",
"secp256r1 (0x17)",
"x448 (0x1e)",
"secp521r1 (0x19)",
"secp384r1 (0x18)",
"ffdhe2048 (0x100)",
"ffdhe3072 (0x101)",
"ffdhe4096 (0x102)",
"ffdhe6144 (0x103)",
"ffdhe8192 (0x104)"
]
},
"ja3_raw": "771,4866-4867-4865-49196-49200-159-52393-52392-52394-49195-49199-158-49188-49192-107-49187-49191-103-49162-49172-57-49161-49171-51-157-156-61-60-53-47-255,0-11-10-16-22-23-49-13-43-45-51-21,29-23-30-25-24-256-257-258-259-260,0-1-2",
"ja4": {
"Protocol": 116,
"TLSVersion": 772,
"SNI": 100,
"NumberOfCipherSuites": 31,
"NumberOfExtensions": 12,
"FirstALPN": "h2",
"CipherSuites": [
47,
51,
53,
57,
60,
61,
103,
107,
156,
157,
158,
159,
255,
4865,
4866,
4867,
49161,
49162,
49171,
49172,
49187,
49188,
49191,
49192,
49195,
49196,
49199,
49200,
52392,
52393,
52394
],
"Extensions": [
10,
11,
13,
21,
22,
23,
43,
45,
49,
51
],
"SignatureAlgorithms": [
1027,
1283,
1539,
2055,
2056,
2074,
2075,
2076,
2057,
2058,
2059,
2052,
2053,
2054,
1025,
1281,
1537,
771,
769,
770,
1026,
1282,
1538
],
"ReadableCipherSuites": [
"TLS_RSA_WITH_AES_128_CBC_SHA (0x2f)",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x33)",
"TLS_RSA_WITH_AES_256_CBC_SHA (0x35)",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x39)",
"TLS_RSA_WITH_AES_128_CBC_SHA256 (0x3c)",
"TLS_RSA_WITH_AES_256_CBC_SHA256 (0x3d)",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (0x67)",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (0x6b)",
"TLS_RSA_WITH_AES_128_GCM_SHA256 (0x9c)",
"TLS_RSA_WITH_AES_256_GCM_SHA384 (0x9d)",
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x9e)",
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x9f)",
"TLS_EMPTY_RENEGOTIATION_INFO_SCSV (0xff)",
"TLS_AES_128_GCM_SHA256 (0x1301)",
"TLS_AES_256_GCM_SHA384 (0x1302)",
"TLS_CHACHA20_POLY1305_SHA256 (0x1303)",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009)",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 (0xc023)",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 (0xc024)",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (0xc027)",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (0xc028)",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)",
...
v0.5.0
This release improved docs and fixed missing priority field in HTTP2 fingerprint under certain scenario. Thanks to @hellodword.
Some timeouts have also been added to the CLI options, allowing users to modify as needed:
-reverse-proxy-flush-interval string
See https://pkg.go.dev/net/http/httputil#ReverseProxy.FlushInterval, equivalent to $REVERSE_PROXY_FLUSH_INTERVAL (default "100ms")
-timeout-http-idle string
See https://pkg.go.dev/net/http#Server.IdleTimeout, equivalent to $TIMEOUT_HTTP_IDLE (default "180s")
-timeout-http-read string
See https://pkg.go.dev/net/http#Server.ReadTimeout, equivalent to $TIMEOUT_HTTP_READ (default "60s")
-timeout-http-write string
See https://pkg.go.dev/net/http#Server.WriteTimeout, equivalent to $TIMEOUT_HTTP_WRITE (default "60s")
-timeout-tls-handshake string
Timeout for TLS handshakes, equivalent to $TIMEOUT_TLS_HANDSHAKE (default "10s")
f0b7407 (HEAD, tag: v0.5.0, origin/master) Add missing priority in the HEADER frame (#8)
b9869b3 Add help text for metrics.
21a2725 Implement HTTP and TLS timeouts in CLI options.
0bb5584 Improve godoc.
v0.4.1
v0.4.0
This release introduced a few new CLI flags, error log improvements, and two breaking changes.
Notable changes listed below.
Breaking Change
In order to keep the code simple and "one and only one solution for one problem", in commit c2473c8, public variable GetReverseProxyHandler
and methods DefaultTLSConfig()
, StartPrometheusClient()
, DefaultReverseProxyHTTPHandler()
, DefaultProxyServer()
have now been removed.
Now with fingerproxy CLI, you can only customize fingerprinting algorithm via GetHeaderInjectors
. To customize reverse proxy or TLS server parameters, see Use as a Library in README.md.
Breaking Change of reverseproxy
Package
HTTPHandler.ReverseProxy
and HTTPHandler.SetReverseProxyRewriteFunc
has been removed in commit b6a145d.
In fact, HTTPHandler.ReverseProxy
is immutable. While calling NewHTTPHandler
, a rewrite function in ReverseProxy is set to support header injection. Changing internal ReverseProxy disables rewrite, which can cause header injectin malfunction.
Clearer Error Log
Some TLS server error logs such as EOF
, connection reset by peer
, and TLS handshake timed-out, now have been suspended in commit ed4366f.
These errors are usually caused by clients or unstable network. To see these logs, specify --verbose
to enable verbose logs.
More Configurable Options in CLI
New flag --duration-metric-buckets
, --preserve-host
are available. Run fingerproxy --help
to get more information.
Fix fingerprint_duration
Metric Prefix
The default metrics prefix fingerproxy_
was missed in fingerprint_duration
metric. Now it has been added. Fingerproxy metrics now look like:
fingerproxy_fingerprint_duration_seconds_bucket
fingerproxy_fingerprint_duration_seconds_count
fingerproxy_fingerprint_duration_seconds_sum
fingerproxy_requests_total
...
Production-Ready (almost 😂)
More tests have been added, such as JA4 tests from the JA4 official repo.
Fingerproxy has been deployed on some staging servers of subscan.io for a few weeks. We currently have 12 Fingerproxy instances, serving ~ 4 millions of requests per day.
In the next few releases, Fingerproxy may become production-ready state. Let's see! 😉
Full Changelog
9d53f51 (HEAD, tag: v0.4.0, origin/master) Fixup e2e test.
c5d72db Add tests for -preserve-host.
ed4366f Suspend some TLS handshake client error log, moved to verbose log.
c2473c8 Breaking change: remove GetReverseProxyHandler, DefaultTLSConfig(), StartPrometheusClient(), DefaultReverseProxyHTTPHandler(), DefaultProxyServer().
b6a145d Breaking change: remove HTTPHandler.ReverseProxy and SetReverseProxyRewriteFunc().
e283cb7 Improve README.
052d130 Implement official JA4 tests. (#6)