yet another potential DoS fix

This commit is contained in:
zefie
2024-05-04 12:14:06 -04:00
parent 59eeda7367
commit ae93620b7a
2 changed files with 111 additions and 102 deletions

View File

@@ -1683,130 +1683,138 @@ async function processRequest(socket, data_hex, skipSecure = false, encryptedReq
socket_sessions[socket.id].headers = headers; socket_sessions[socket.id].headers = headers;
} }
} else if (socket.ssid) { } else if (socket.ssid) {
// handle streaming POST try {
if (socket_sessions[socket.id].expecting_post_data && headers) { // handle streaming POST
socket_sessions[socket.id].headers = headers; if (socket_sessions[socket.id].expecting_post_data && headers) {
if (socket_sessions[socket.id].post_data.length < (socket_sessions[socket.id].post_data_length * 2)) { if (socket_sessions[socket.id].post_data_length > (minisrv_config.config.max_post_length * 1024 * 1024)) {
new_header_obj = null; closeSocket(socket);
var enc_data = CryptoJS.enc.Hex.parse(data_hex);
if (socket_sessions[socket.id].secure) {
// decrypt if encrypted
var dec_data = CryptoJS.lib.WordArray.create(socket_sessions[socket.id].wtvsec.Decrypt(0, enc_data))
} else { } else {
// just pass it over socket_sessions[socket.id].headers = headers;
var dec_data = enc_data; if (socket_sessions[socket.id].post_data.length < (socket_sessions[socket.id].post_data_length * 2)) {
} new_header_obj = null;
var enc_data = CryptoJS.enc.Hex.parse(data_hex);
if (socket_sessions[socket.id].secure) {
// decrypt if encrypted
var dec_data = CryptoJS.lib.WordArray.create(socket_sessions[socket.id].wtvsec.Decrypt(0, enc_data))
} else {
// just pass it over
var dec_data = enc_data;
}
socket_sessions[socket.id].post_data += dec_data.toString(CryptoJS.enc.Hex); socket_sessions[socket.id].post_data += dec_data.toString(CryptoJS.enc.Hex);
var post_string = "POST"; var post_string = "POST";
if (socket_sessions[socket.id].secure == true) post_string = "Encrypted " + post_string; if (socket_sessions[socket.id].secure == true) post_string = "Encrypted " + post_string;
if (minisrv_config.config.post_debug) { if (minisrv_config.config.post_debug) {
// `post_debug` logging of every chunk // `post_debug` logging of every chunk
console.log(" * ", Math.floor(new Date().getTime() / 1000), "Receiving", post_string, "data on", socket.id, "[", socket_sessions[socket.id].post_data.length / 2, "of", socket_sessions[socket.id].post_data_length, "bytes ]"); console.log(" * ", Math.floor(new Date().getTime() / 1000), "Receiving", post_string, "data on", socket.id, "[", socket_sessions[socket.id].post_data.length / 2, "of", socket_sessions[socket.id].post_data_length, "bytes ]");
} else { } else {
// calculate and display percentage of data received // calculate and display percentage of data received
var postPercent = wtvshared.getPercentage(socket_sessions[socket.id].post_data.length, (socket_sessions[socket.id].post_data_length * 2)); var postPercent = wtvshared.getPercentage(socket_sessions[socket.id].post_data.length, (socket_sessions[socket.id].post_data_length * 2));
if (minisrv_config.config.post_percentages) { if (minisrv_config.config.post_percentages) {
if (minisrv_config.config.post_percentages.includes(postPercent)) { if (minisrv_config.config.post_percentages.includes(postPercent)) {
if (!socket_sessions[socket.id].post_data_percents_shown) socket_sessions[socket.id].post_data_percents_shown = new Array(); if (!socket_sessions[socket.id].post_data_percents_shown) socket_sessions[socket.id].post_data_percents_shown = new Array();
if (!socket_sessions[socket.id].post_data_percents_shown[postPercent]) { if (!socket_sessions[socket.id].post_data_percents_shown[postPercent]) {
console.log(" * Received", postPercent, "% of", socket_sessions[socket.id].post_data_length, "bytes on", socket.id, "from", wtvshared.filterSSID(socket.ssid)); console.log(" * Received", postPercent, "% of", socket_sessions[socket.id].post_data_length, "bytes on", socket.id, "from", wtvshared.filterSSID(socket.ssid));
socket_sessions[socket.id].post_data_percents_shown[postPercent] = true; socket_sessions[socket.id].post_data_percents_shown[postPercent] = true;
}
if (postPercent == 100) delete socket_sessions[socket.id].post_data_percents_shown;
}
} }
if (postPercent == 100) delete socket_sessions[socket.id].post_data_percents_shown;
} }
} }
} if (socket_sessions[socket.id].post_data.length == (socket_sessions[socket.id].post_data_length * 2)) {
} // got all expected data
if (socket_sessions[socket.id].post_data.length == (socket_sessions[socket.id].post_data_length * 2)) { if (socket_sessions[socket.id].expecting_post_data) delete socket_sessions[socket.id].expecting_post_data;
// got all expected data socket.setTimeout(minisrv_config.config.socket_timeout * 1000);
if (socket_sessions[socket.id].expecting_post_data) delete socket_sessions[socket.id].expecting_post_data; headers.post_data = CryptoJS.enc.Hex.parse(socket_sessions[socket.id].post_data);
socket.setTimeout(minisrv_config.config.socket_timeout * 1000); if (socket_sessions[socket.id].secure == true) {
headers.post_data = CryptoJS.enc.Hex.parse(socket_sessions[socket.id].post_data); if (minisrv_config.config.debug_flags.debug) console.log(" # Encrypted POST Content (SECURE ON)", "on", socket.id, "[", headers.post_data.sigBytes, "bytes ]");
if (socket_sessions[socket.id].secure == true) { } else {
if (minisrv_config.config.debug_flags.debug) console.log(" # Encrypted POST Content (SECURE ON)", "on", socket.id, "[", headers.post_data.sigBytes, "bytes ]"); if (minisrv_config.config.debug_flags.debug) console.log(" # Unencrypted POST Content", "on", socket.id);
} else { }
if (minisrv_config.config.debug_flags.debug) console.log(" # Unencrypted POST Content", "on", socket.id); socket_sessions[socket.id].expecting_post_data = false;
} delete socket_sessions[socket.id].headers;
socket_sessions[socket.id].expecting_post_data = false; delete socket_sessions[socket.id].post_data;
delete socket_sessions[socket.id].headers; delete socket_sessions[socket.id].post_data_length;
delete socket_sessions[socket.id].post_data; processURL(socket, headers);
delete socket_sessions[socket.id].post_data_length; return;
processURL(socket, headers); } else if (socket_sessions[socket.id].post_data.length > (socket_sessions[socket.id].post_data_length * 2)) {
return; socket_sessions[socket.id].expecting_post_data = false;
} else if (socket_sessions[socket.id].post_data.length > (socket_sessions[socket.id].post_data_length * 2)) { if (socket_sessions[socket.id].expecting_post_data) delete socket_sessions[socket.id].expecting_post_data;
socket_sessions[socket.id].expecting_post_data = false; socket.setTimeout(minisrv_config.config.socket_timeout * 1000);
if (socket_sessions[socket.id].expecting_post_data) delete socket_sessions[socket.id].expecting_post_data; // got too much data ? ... should not ever reach this code
socket.setTimeout(minisrv_config.config.socket_timeout * 1000); var errpage = wtvshared.doErrorPage(400, null, "Received too much data in POST request<br>Got " + (socket_sessions[socket.id].post_data.length / 2) + ", expected " + socket_sessions[socket.id].post_data_length);
// got too much data ? ... should not ever reach this code headers = errpage[0];
var errpage = wtvshared.doErrorPage(400, null, "Received too much data in POST request<br>Got " + (socket_sessions[socket.id].post_data.length / 2) + ", expected " + socket_sessions[socket.id].post_data_length);
headers = errpage[0];
data = errpage[1];
sendToClient(socket, headers, data);
return;
}
} else if (!skipSecure) {
if (!encryptedRequest) {
if (socket_sessions[socket.id].secure != true) {
socket_sessions[socket.id].wtvsec = new WTVSec(minisrv_config);
socket_sessions[socket.id].wtvsec.IssueChallenge();
socket_sessions[socket.id].wtvsec.SecureOn();
socket_sessions[socket.id].secure = true;
}
var enc_data = CryptoJS.enc.Hex.parse(data_hex);
if (enc_data.sigBytes > 0) {
if (!socket_sessions[socket.id].wtvsec) {
var errpage = wtvshared.doErrorPage(400);
var headers = errpage[0];
headers += "wtv-visit: client:relog\n";
data = errpage[1]; data = errpage[1];
sendToClient(socket, headers, data); sendToClient(socket, headers, data);
return; return;
} }
var str_test = enc_data.toString(CryptoJS.enc.Latin1); }
if (isUnencryptedString(str_test)) { } else if (!skipSecure) {
var dec_data = enc_data; if (!encryptedRequest) {
} else { if (socket_sessions[socket.id].secure != true) {
var dec_data = CryptoJS.lib.WordArray.create(socket_sessions[socket.id].wtvsec.Decrypt(0, enc_data)); socket_sessions[socket.id].wtvsec = new WTVSec(minisrv_config);
socket_sessions[socket.id].wtvsec.IssueChallenge();
socket_sessions[socket.id].wtvsec.SecureOn();
socket_sessions[socket.id].secure = true;
} }
if (!socket_sessions[socket.id].secure_buffer) socket_sessions[socket.id].secure_buffer = ""; var enc_data = CryptoJS.enc.Hex.parse(data_hex);
socket_sessions[socket.id].secure_buffer += dec_data.toString(CryptoJS.enc.Hex); if (enc_data.sigBytes > 0) {
var secure_headers = null; if (!socket_sessions[socket.id].wtvsec) {
if (headers['request']) { var errpage = wtvshared.doErrorPage(400);
if (headers['request'] == "GET") { var headers = errpage[0];
if (socket_sessions[socket.id].secure_buffer.indexOf("0d0a0d0a") || socket_sessions[socket.id].secure_buffer.indexOf("0a0a")) { headers += "wtv-visit: client:relog\n";
secure_headers = await processRequest(socket, socket_sessions[socket.id].secure_buffer, true, true); data = errpage[1];
sendToClient(socket, headers, data);
return;
}
var str_test = enc_data.toString(CryptoJS.enc.Latin1);
if (isUnencryptedString(str_test)) {
var dec_data = enc_data;
} else {
var dec_data = CryptoJS.lib.WordArray.create(socket_sessions[socket.id].wtvsec.Decrypt(0, enc_data));
}
if (!socket_sessions[socket.id].secure_buffer) socket_sessions[socket.id].secure_buffer = "";
socket_sessions[socket.id].secure_buffer += dec_data.toString(CryptoJS.enc.Hex);
var secure_headers = null;
if (headers['request']) {
if (headers['request'] == "GET") {
if (socket_sessions[socket.id].secure_buffer.indexOf("0d0a0d0a") || socket_sessions[socket.id].secure_buffer.indexOf("0a0a")) {
secure_headers = await processRequest(socket, socket_sessions[socket.id].secure_buffer, true, true);
}
} else {
var secure_headers = await processRequest(socket, socket_sessions[socket.id].secure_buffer, true, true);
} }
} else { } else {
var secure_headers = await processRequest(socket, socket_sessions[socket.id].secure_buffer, true, true); var secure_headers = await processRequest(socket, socket_sessions[socket.id].secure_buffer, true, true);
} }
} else { if (secure_headers) {
var secure_headers = await processRequest(socket, socket_sessions[socket.id].secure_buffer, true, true); delete socket_sessions[socket.id].secure_buffer;
} if (!headers) headers = new Array();
if (secure_headers) { headers.encrypted = true;
delete socket_sessions[socket.id].secure_buffer; Object.keys(secure_headers).forEach(function (k, v) {
if (!headers) headers = new Array(); headers[k] = secure_headers[k];
headers.encrypted = true; });
Object.keys(secure_headers).forEach(function (k, v) { if (headers['request']) {
headers[k] = secure_headers[k]; if (headers['request'].substring(0, 4) == "POST") {
}); if (!socket_sessions[socket.id].post_data) {
if (headers['request']) { socket_sessions[socket.id].post_data_length = headers['Content-length'] || headers['Content-Length'] || 0;
if (headers['request'].substring(0, 4) == "POST") { socket_sessions[socket.id].post_data = "";
if (!socket_sessions[socket.id].post_data) { }
socket_sessions[socket.id].post_data_length = headers['Content-length'] || headers['Content-Length'] || 0; processRequest(socket, dec_data.toString(CryptoJS.enc.Hex));
socket_sessions[socket.id].post_data = ""; } else {
processURL(socket, headers);
} }
processRequest(socket, dec_data.toString(CryptoJS.enc.Hex));
} else {
processURL(socket, headers);
} }
} }
} }
} }
} else {
cleanupSocket(socket);
} }
} else { } catch (e) {
cleanupSocket(socket); cleanupSocket(socket);
} }
} else { } else {

View File

@@ -46,6 +46,7 @@
"enable_port_isolation": true, // Only respond to services on their correct ports "enable_port_isolation": true, // Only respond to services on their correct ports
"allow_guests": true, // Allow users to experience the server without registering "allow_guests": true, // Allow users to experience the server without registering
"domain_name": "wtv.zefie.com", // For usenet and future stuff, no need to change just yet, "domain_name": "wtv.zefie.com", // For usenet and future stuff, no need to change just yet,
"max_post_length": 20, // in megabytes
"user_accounts": { // user account settings "user_accounts": { // user account settings
"max_users_per_account": 6, // Max total users (including primary) per account "max_users_per_account": 6, // Max total users (including primary) per account
"min_username_length": 5, // minimum username length "min_username_length": 5, // minimum username length