From d2e5b6542f71f3809ba94d56c26f382b5cb62762 Mon Sep 17 00:00:00 2001 From: jj Date: Sat, 15 Jun 2024 18:20:33 +0200 Subject: [PATCH] api: randomize cipherlist for making requests to services (#574) this makes cobalt less prone to TLS client fingerprinting, as it avoids having the default node.js TLS fingerprint that is shared by all node.js applications. --- src/core/api.js | 4 ++++ src/modules/sub/randomize-ciphers.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/modules/sub/randomize-ciphers.js diff --git a/src/core/api.js b/src/core/api.js index c90f78f7..a366ad09 100644 --- a/src/core/api.js +++ b/src/core/api.js @@ -10,6 +10,7 @@ import loc from "../localization/manager.js"; import { createResponse, normalizeRequest, getIP } from "../modules/processing/request.js"; import { verifyStream, getInternalStream } from "../modules/stream/manage.js"; +import { randomizeCiphers } from '../modules/sub/randomize-ciphers.js'; import { extract } from "../modules/processing/url.js"; import match from "../modules/processing/match.js"; import stream from "../modules/stream/stream.js"; @@ -215,6 +216,9 @@ export function runAPI(express, app, gitCommit, gitBranch, __dirname) { res.redirect('/api/serverInfo') }) + randomizeCiphers(); + setInterval(randomizeCiphers, 1000 * 60 * 30); // shuffle ciphers every 30 minutes + app.listen(env.apiPort, env.listenAddress, () => { console.log(`\n` + `${Cyan("cobalt")} API ${Bright(`v.${version}-${gitCommit} (${gitBranch})`)}\n` + diff --git a/src/modules/sub/randomize-ciphers.js b/src/modules/sub/randomize-ciphers.js new file mode 100644 index 00000000..e11e1ee2 --- /dev/null +++ b/src/modules/sub/randomize-ciphers.js @@ -0,0 +1,28 @@ +import tls from 'node:tls'; +import { randomBytes } from 'node:crypto'; + +const ORIGINAL_CIPHERS = tls.DEFAULT_CIPHERS; + +// How many ciphers from the top of the list to shuffle. +// The remaining ciphers are left in the original order. +const TOP_N_SHUFFLE = 8; + +// Modified variation of https://stackoverflow.com/a/12646864 +const shuffleArray = (array) => { + for (let i = array.length - 1; i > 0; i--) { + const j = randomBytes(4).readUint32LE() % array.length; + [array[i], array[j]] = [array[j], array[i]]; + } + + return array; +} + +export const randomizeCiphers = () => { + do { + const cipherList = ORIGINAL_CIPHERS.split(':'); + const shuffled = shuffleArray(cipherList.slice(0, TOP_N_SHUFFLE)); + const retained = cipherList.slice(TOP_N_SHUFFLE); + + tls.DEFAULT_CIPHERS = [ ...shuffled, ...retained ].join(':'); + } while (tls.DEFAULT_CIPHERS === ORIGINAL_CIPHERS); +}