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.
This commit is contained in:
jj 2024-06-15 18:20:33 +02:00 committed by GitHub
parent 1d5fa62271
commit d2e5b6542f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 32 additions and 0 deletions

View file

@ -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` +

View file

@ -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);
}