forked from cory/tildefriends
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:
parent
2826efea56
commit
87224d2bb6
@ -603,6 +603,8 @@ loadSettings().then(function() {
|
|||||||
httpd.registerSocketHandler("/app/socket", app.socket);
|
httpd.registerSocketHandler("/app/socket", app.socket);
|
||||||
}).catch(function(error) {
|
}).catch(function(error) {
|
||||||
print('Failed to load settings.');
|
print('Failed to load settings.');
|
||||||
|
print(error);
|
||||||
|
exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
exports.getSessionProcessBlob = getSessionProcessBlob;
|
exports.getSessionProcessBlob = getSessionProcessBlob;
|
||||||
|
@ -2,9 +2,13 @@
|
|||||||
|
|
||||||
var gHandlers = [];
|
var gHandlers = [];
|
||||||
var gSocketHandlers = [];
|
var gSocketHandlers = [];
|
||||||
|
var gBadRequests = {};
|
||||||
|
|
||||||
function logError(error) {
|
function logError(error) {
|
||||||
print("ERROR " + error);
|
print("ERROR " + error);
|
||||||
|
if (error.stackTrace) {
|
||||||
|
print(error.stackTrace);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addHandler(handler) {
|
function addHandler(handler) {
|
||||||
@ -48,7 +52,7 @@ function Request(method, uri, version, headers, body, client) {
|
|||||||
this.uri = uri;
|
this.uri = uri;
|
||||||
this.query = undefined;
|
this.query = undefined;
|
||||||
}
|
}
|
||||||
this.version = version;
|
this.version = version || '';
|
||||||
this.headers = headers;
|
this.headers = headers;
|
||||||
this.client = {peerName: client.peerName, tls: client.tls};
|
this.client = {peerName: client.peerName, tls: client.tls};
|
||||||
this.body = body;
|
this.body = body;
|
||||||
@ -127,7 +131,7 @@ function Response(request, client) {
|
|||||||
}
|
}
|
||||||
headerString += "\r\n";
|
headerString += "\r\n";
|
||||||
_started = true;
|
_started = true;
|
||||||
client.write(headerString);
|
client.write(headerString).catch(function() {});
|
||||||
},
|
},
|
||||||
end: function(data) {
|
end: function(data) {
|
||||||
if (_finished) {
|
if (_finished) {
|
||||||
@ -135,25 +139,24 @@ function Response(request, client) {
|
|||||||
}
|
}
|
||||||
if (data) {
|
if (data) {
|
||||||
if (_chunked) {
|
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 {
|
} else {
|
||||||
client.write(data);
|
client.write(data).catch(function() {});
|
||||||
}
|
}
|
||||||
} else if (_chunked) {
|
} else if (_chunked) {
|
||||||
client.write("0\r\n\r\n");
|
client.write("0\r\n\r\n").catch(function() {});
|
||||||
}
|
}
|
||||||
_finished = true;
|
_finished = true;
|
||||||
if (!_keepAlive) {
|
if (!_keepAlive) {
|
||||||
client.shutdown();
|
client.shutdown().catch(function() {});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
reportError: function(error) {
|
reportError: function(error) {
|
||||||
if (!_started) {
|
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) {
|
if (!_finished) {
|
||||||
client.write("500 Internal Server Error\r\n\r\n" + error.stackTrace);
|
client.write("500 Internal Server Error\r\n\r\n" + error?.stackTrace).catch(function() {});
|
||||||
client.shutdown();
|
|
||||||
}
|
}
|
||||||
logError(client.peerName + " - - [" + new Date() + "] " + error);
|
logError(client.peerName + " - - [" + new Date() + "] " + error);
|
||||||
},
|
},
|
||||||
@ -175,7 +178,6 @@ function handleRequest(request, response) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
print(error);
|
|
||||||
response.reportError(error);
|
response.reportError(error);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -344,7 +346,46 @@ function webSocketAcceptResponse(key) {
|
|||||||
return binary;
|
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) {
|
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 inputBuffer = new Uint8Array(0);
|
||||||
var request;
|
var request;
|
||||||
var headers = {};
|
var headers = {};
|
||||||
@ -378,7 +419,16 @@ function handleConnection(client) {
|
|||||||
if (bodyToRead == -1) {
|
if (bodyToRead == -1) {
|
||||||
line = utf8Decode(line);
|
line = utf8Decode(line);
|
||||||
if (!request) {
|
if (!request) {
|
||||||
|
if (!line) {
|
||||||
|
badRequest(client, 'Empty request.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
request = line.split(' ');
|
request = line.split(' ');
|
||||||
|
if (request.length != 3 || !request[2].startsWith('HTTP/1.')) {
|
||||||
|
badRequest(client, 'Bad request.');
|
||||||
|
request = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
} else if (line) {
|
} else if (line) {
|
||||||
var colon = line.indexOf(':');
|
var colon = line.indexOf(':');
|
||||||
@ -390,6 +440,10 @@ function handleConnection(client) {
|
|||||||
if (headers["content-length"] != undefined) {
|
if (headers["content-length"] != undefined) {
|
||||||
bodyToRead = parseInt(headers["content-length"]);
|
bodyToRead = parseInt(headers["content-length"]);
|
||||||
lineByLine = false;
|
lineByLine = false;
|
||||||
|
if (bodyToRead > 16 * 1024 * 1024) {
|
||||||
|
badRequest(client, 'Reuqest too large: ' + bodyToRead + '.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
body = new Uint8Array(bodyToRead);
|
body = new Uint8Array(bodyToRead);
|
||||||
return true;
|
return true;
|
||||||
} else if (headers["connection"]
|
} else if (headers["connection"]
|
||||||
@ -426,6 +480,7 @@ function handleConnection(client) {
|
|||||||
|
|
||||||
client.read(function(data) {
|
client.read(function(data) {
|
||||||
if (data) {
|
if (data) {
|
||||||
|
const kMaxLineLength = 4096;
|
||||||
var newBuffer = new Uint8Array(inputBuffer.length + data.length);
|
var newBuffer = new Uint8Array(inputBuffer.length + data.length);
|
||||||
newBuffer.set(inputBuffer, 0);
|
newBuffer.set(inputBuffer, 0);
|
||||||
newBuffer.set(data, inputBuffer.length);
|
newBuffer.set(data, inputBuffer.length);
|
||||||
@ -443,6 +498,10 @@ function handleConnection(client) {
|
|||||||
if (end > 0 && inputBuffer[end - 1] == carriageReturn) {
|
if (end > 0 && inputBuffer[end - 1] == carriageReturn) {
|
||||||
--end;
|
--end;
|
||||||
}
|
}
|
||||||
|
if (end > kMaxLineLength || end == -1 && inputBuffer.length > kMaxLineLength) {
|
||||||
|
badRequest(client, 'Request too long.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (end != -1) {
|
if (end != -1) {
|
||||||
var line = inputBuffer.slice(0, end);
|
var line = inputBuffer.slice(0, end);
|
||||||
inputBuffer = inputBuffer.slice(realEnd + 1);
|
inputBuffer = inputBuffer.slice(realEnd + 1);
|
||||||
|
Loading…
Reference in New Issue
Block a user