Add some protection against bad requests. Also bail if we can't start properly.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3870 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
Cory McWilliams 2022-04-26 23:05:02 +00:00
parent 2826efea56
commit 87224d2bb6
2 changed files with 71 additions and 10 deletions

View File

@ -603,6 +603,8 @@ loadSettings().then(function() {
httpd.registerSocketHandler("/app/socket", app.socket);
}).catch(function(error) {
print('Failed to load settings.');
print(error);
exit(1);
});
exports.getSessionProcessBlob = getSessionProcessBlob;

View File

@ -2,9 +2,13 @@
var gHandlers = [];
var gSocketHandlers = [];
var gBadRequests = {};
function logError(error) {
print("ERROR " + error);
if (error.stackTrace) {
print(error.stackTrace);
}
}
function addHandler(handler) {
@ -48,7 +52,7 @@ function Request(method, uri, version, headers, body, client) {
this.uri = uri;
this.query = undefined;
}
this.version = version;
this.version = version || '';
this.headers = headers;
this.client = {peerName: client.peerName, tls: client.tls};
this.body = body;
@ -127,7 +131,7 @@ function Response(request, client) {
}
headerString += "\r\n";
_started = true;
client.write(headerString);
client.write(headerString).catch(function() {});
},
end: function(data) {
if (_finished) {
@ -135,25 +139,24 @@ function Response(request, client) {
}
if (data) {
if (_chunked) {
client.write(data.length.toString(16) + "\r\n" + data + "\r\n" + "0\r\n\r\n");
client.write(data.length.toString(16) + "\r\n" + data + "\r\n" + "0\r\n\r\n").catch(function() {});
} else {
client.write(data);
client.write(data).catch(function() {});
}
} else if (_chunked) {
client.write("0\r\n\r\n");
client.write("0\r\n\r\n").catch(function() {});
}
_finished = true;
if (!_keepAlive) {
client.shutdown();
client.shutdown().catch(function() {});
}
},
reportError: function(error) {
if (!_started) {
client.write("HTTP/1.1 500 Internal Server Error\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n");
client.write("HTTP/1.1 500 Internal Server Error\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n").catch(function() {});
}
if (!_finished) {
client.write("500 Internal Server Error\r\n\r\n" + error.stackTrace);
client.shutdown();
client.write("500 Internal Server Error\r\n\r\n" + error?.stackTrace).catch(function() {});
}
logError(client.peerName + " - - [" + new Date() + "] " + error);
},
@ -175,7 +178,6 @@ function handleRequest(request, response) {
});
}
} catch (error) {
print(error);
response.reportError(error);
}
} else {
@ -344,7 +346,46 @@ function webSocketAcceptResponse(key) {
return binary;
}
function badRequest(client, reason) {
var now = new Date();
var count = 0;
var old = gBadRequests[client.peerName];
if (!old) {
gBadRequests[client.peerName] = {
expire: new Date(now.getTime() + 10 * 60 * 1000),
count: 1,
};
count = 1;
} else {
old.count++;
count = old.count;
}
new Response({version: '1.0'}, client).reportError(reason + ': ' + count);
client.close();
}
function allowRequest(client) {
var old = gBadRequests[client.peerName];
if (old) {
var now = new Date();
if (old.expire < now) {
delete gBadRequests[client.peerName];
return true;
} else {
return old.count < 3;
}
} else {
return true;
}
}
function handleConnection(client) {
if (!allowRequest(client)) {
print('Rejecting client for too many bad requests: ', client.peerName);
client.close();
return;
}
var inputBuffer = new Uint8Array(0);
var request;
var headers = {};
@ -378,7 +419,16 @@ function handleConnection(client) {
if (bodyToRead == -1) {
line = utf8Decode(line);
if (!request) {
if (!line) {
badRequest(client, 'Empty request.');
return false;
}
request = line.split(' ');
if (request.length != 3 || !request[2].startsWith('HTTP/1.')) {
badRequest(client, 'Bad request.');
request = null;
return false;
}
return true;
} else if (line) {
var colon = line.indexOf(':');
@ -390,6 +440,10 @@ function handleConnection(client) {
if (headers["content-length"] != undefined) {
bodyToRead = parseInt(headers["content-length"]);
lineByLine = false;
if (bodyToRead > 16 * 1024 * 1024) {
badRequest(client, 'Reuqest too large: ' + bodyToRead + '.');
return false;
}
body = new Uint8Array(bodyToRead);
return true;
} else if (headers["connection"]
@ -426,6 +480,7 @@ function handleConnection(client) {
client.read(function(data) {
if (data) {
const kMaxLineLength = 4096;
var newBuffer = new Uint8Array(inputBuffer.length + data.length);
newBuffer.set(inputBuffer, 0);
newBuffer.set(data, inputBuffer.length);
@ -443,6 +498,10 @@ function handleConnection(client) {
if (end > 0 && inputBuffer[end - 1] == carriageReturn) {
--end;
}
if (end > kMaxLineLength || end == -1 && inputBuffer.length > kMaxLineLength) {
badRequest(client, 'Request too long.');
return;
}
if (end != -1) {
var line = inputBuffer.slice(0, end);
inputBuffer = inputBuffer.slice(realEnd + 1);