mirror of
https://github.com/netbirdio/plugins.git
synced 2026-05-22 18:44:07 -07:00
www/nginx: tls fingerprints rfc8701 compat. (#3018)
* typo * rfc8701 * rfc8701 * includes * version bump * ignore SCSVs (rfc5746 and rfc7507) * add http_post hook so we can add maps if needed * Update pkg-descr
This commit is contained in:
+1
-2
@@ -1,6 +1,5 @@
|
||||
PLUGIN_NAME= nginx
|
||||
PLUGIN_VERSION= 1.28
|
||||
PLUGIN_REVISION= 2
|
||||
PLUGIN_VERSION= 1.29
|
||||
PLUGIN_COMMENT= Nginx HTTP server and reverse proxy
|
||||
PLUGIN_DEPENDS= nginx
|
||||
PLUGIN_MAINTAINER= franz.fabian.94@gmail.com
|
||||
|
||||
@@ -10,6 +10,13 @@ WWW: https://nginx.org/
|
||||
Plugin Changelog
|
||||
================
|
||||
|
||||
1.29
|
||||
|
||||
* fixed a typo in the trusted tls fingerprints db creation part of setup.php
|
||||
* rfc5746, rfc7507 and rfc8701 are taken into account on compiling and comparing tls fingerprints
|
||||
* the reason for scoring the connection as intercepted is added to the X-TLS-Client-Intercepted header. check backend settings if using this feature
|
||||
* http_post hook added to be able to map global variables
|
||||
|
||||
1.28
|
||||
|
||||
* add support for connect-src and worker-src in content security policy
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
var fs = require('fs');
|
||||
var tls_fingerprints = JSON.parse(fs.readFileSync('/usr/local/etc/nginx/tls_fingerprints.json'));
|
||||
// ignore GREASE cipher suite values when compiling a browser fingerprint (see rfc8701)
|
||||
const GREASE = ["0x0a0a", "0x1a1a", "0x2a2a", "0x3a3a", "0x4a4a", "0x5a5a", "0x6a6a", "0x7a7a", "0x8a8a", "0x9a9a", "0xaaaa", "0xbaba", "0xcaca", "0xdada", "0xeaea", "0xfafa"];
|
||||
// ignore SCSV cipher suite values when compiling a browser fingerprint (see rfc5746 and rfc7507)
|
||||
const SCSV = ["TLS_EMPTY_RENEGOTIATION_INFO_SCSV", "TLS_FALLBACK_SCSV"];
|
||||
|
||||
function check_cipher_array(r, browser_ciphers, fingerprint_ciphers, result) {
|
||||
if (result.status == 'Intercepted') {
|
||||
if (result.status.includes('Intercepted')) {
|
||||
return;
|
||||
}
|
||||
if (browser_ciphers.length > fingerprint_ciphers.length) {
|
||||
// the proxy supports more cipers than the browser -> intercepted
|
||||
result.status = "Intercepted";
|
||||
// the proxy supports more ciphers than the browser -> intercepted
|
||||
result.status = "Intercepted; Reason=\"excess suite\"";
|
||||
return;
|
||||
}
|
||||
var browser_cipher;
|
||||
@@ -18,9 +22,9 @@ function check_cipher_array(r, browser_ciphers, fingerprint_ciphers, result) {
|
||||
browser_cipher = browser_ciphers[browser_cipher_index];
|
||||
current_index = fingerprint_ciphers.indexOf(browser_cipher);
|
||||
if (current_index === -1 || current_index <= last_index) {
|
||||
// a cipher has been found, which is not supported by the browser
|
||||
// a cipher has been found, which is not supported by the browser or order of preference changed
|
||||
// such a connection is definitly intercepted
|
||||
result.status = "Intercepted";
|
||||
result.status = "Intercepted; Reason=\"excess suite or wrong order\"";
|
||||
return;
|
||||
}
|
||||
last_index = current_index;
|
||||
@@ -36,11 +40,23 @@ function check_intercept(r) {
|
||||
var ua = r.headersIn['User-Agent'];
|
||||
if (ua in tls_fingerprints) {
|
||||
var fp = tls_fingerprints[ua];
|
||||
fp.ciphers = fp.ciphers.filter( function( el ) {
|
||||
return ((GREASE.indexOf( el ) < 0) && (SCSV.indexOf( el ) < 0));
|
||||
} );
|
||||
fp.curves = fp.curves.filter( function( el ) {
|
||||
return GREASE.indexOf( el ) < 0;
|
||||
} );
|
||||
var browser_ciphers = r.variables.ssl_ciphers.split(':');
|
||||
browser_ciphers = browser_ciphers.filter( function( el ) {
|
||||
return ((GREASE.indexOf( el ) < 0) && (SCSV.indexOf( el ) < 0));
|
||||
} );
|
||||
check_cipher_array(r, browser_ciphers, fp.ciphers, tls_result);
|
||||
if (r.variables.ssl_curves != '')
|
||||
{
|
||||
var browser_curves = r.variables.ssl_curves.split(':');
|
||||
browser_curves = browser_curves.filter( function( el ) {
|
||||
return GREASE.indexOf( el ) < 0;
|
||||
} );
|
||||
check_cipher_array(r, browser_curves, fp.curves, tls_result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,7 +304,7 @@ foreach ($nginx->tls_fingerprint->iterateItems() as $tls_fingerprint) {
|
||||
if ((string)$tls_fingerprint->trusted == '1') {
|
||||
$ciphers = explode(':', (string)$tls_fingerprint->ciphers);
|
||||
if (!empty((string)$tls_fingerprint->curves)) {
|
||||
$curves = explode(':', (string)$tls_fingerprint->ciphers);
|
||||
$curves = explode(':', (string)$tls_fingerprint->curves);
|
||||
} else {
|
||||
$curves = array();
|
||||
}
|
||||
|
||||
@@ -31,13 +31,25 @@ $database_name = '/var/log/nginx/handshakes.json';
|
||||
|
||||
function parse_line($line)
|
||||
{
|
||||
// ignore GREASE cipher suite values when compiling a browser fingerprint (see rfc8701)
|
||||
$GREASE = array("0x0a0a", "0x1a1a", "0x2a2a", "0x3a3a", "0x4a4a", "0x5a5a", "0x6a6a", "0x7a7a", "0x8a8a", "0x9a9a", "0xaaaa", "0xbaba", "0xcaca", "0xdada", "0xeaea", "0xfafa");
|
||||
// ignore SCSV cipher suite values when compiling a browser fingerprint (see rfc5746 and rfc7507)
|
||||
$SCSV = array("TLS_EMPTY_RENEGOTIATION_INFO_SCSV", "TLS_FALLBACK_SCSV");
|
||||
$tmp = explode('"', trim($line));
|
||||
return array(
|
||||
$fp = array(
|
||||
'ua' => $tmp[1],
|
||||
'ciphers' => $tmp[3],
|
||||
'curves' => $tmp[5] == '-' ? '' : $tmp[5],
|
||||
'count' => 1
|
||||
);
|
||||
// exclude GREASE and SCSV suits from fingerprint
|
||||
$fp_ciphers = explode(':', $fp['ciphers']);
|
||||
$fp_ciphers = array_diff($fp_ciphers, $GREASE, $SCSV);
|
||||
$fp['ciphers'] = implode(':', $fp_ciphers);
|
||||
$fp_curves = explode(':', $fp['curves']);
|
||||
$fp_curves = array_diff($fp_curves, $GREASE);
|
||||
$fp['curves'] = implode(':', $fp_curves);
|
||||
return $fp;
|
||||
}
|
||||
function filter_ua($key)
|
||||
{
|
||||
@@ -61,13 +73,13 @@ $fingerprints = array();
|
||||
$handle = @fopen($tls_logfile, 'r');
|
||||
if ($handle) {
|
||||
while (($buffer = fgets($handle)) !== false) {
|
||||
$md5line = md5($buffer);
|
||||
if (array_key_exists($md5line, $fingerprints)) {
|
||||
$fingerprints[$md5line]['count']++;
|
||||
} else {
|
||||
$parsed_line = parse_line($buffer);
|
||||
if ($parsed_line['ciphers'] != '-') {
|
||||
$fingerprints[$md5line] = $parsed_line;
|
||||
$parsed_line = parse_line($buffer);
|
||||
if ($parsed_line['ciphers'] != '-') {
|
||||
$md5fp = md5($parsed_line['ua'] . $parsed_line['ciphers'] . $parsed_line['curves']);
|
||||
if (array_key_exists($md5fp, $fingerprints)) {
|
||||
$fingerprints[$md5fp]['count']++;
|
||||
} else {
|
||||
$fingerprints[$md5fp] = $parsed_line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,8 @@ map $http_upgrade $connection_upgrade {
|
||||
'' close;
|
||||
}
|
||||
|
||||
include http_post/*.conf;
|
||||
|
||||
# TODO add when core is ready for allowing nginx to serve the web interface
|
||||
# include nginx_web.conf;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user