This repository was archived by the owner on Oct 7, 2020. It is now read-only.
This repository was archived by the owner on Oct 7, 2020. It is now read-only.
http: sanitize http headers and method names #13
Closed
Description
Simple test case:
var http = require('http');
var server = http.createServer(function(req, res) {
res.setHeader('Foo\n\nBar', 'Value');
res.end();
});
server.listen(3000, function() {
console.log('server started');
});
Then do a curl -v http://localhost:3000
This is not a new issue (nodejs/node-v0.x-archive#2602, nodejs/node-v0.x-archive#9076). It affects HTTP request methods and header names. It happens in v0.10
, v0.12
, and current io.js:
var http = require('http');
var server = http.createServer(function(req,res) {
res.writeHead(200, {'Foo\n\nBar': 'Value'});
res.end('okay');
});
server.listen(3000, function() { console.log('started'); });
I have the code written up to perform the necessary fix but I need a decision: when an invalid http method or header name is passed in, should we throw or attempt to sanitize? Throwing is a API change that breaks backwards compatibility but this is an obvious error with potential security ramifications (fairly low risk). Sanitizing can lead to unexpected results and there is no standard pattern we can follow. Throwing seems to be the best approach.
// http token is defined in RFC2616 as...
// token = 1*<any CHAR except CTLs or separators>
// separators = "(" | ")" | "<" | ">" | "@"
// | "," | ";" | ":" | "\" | <">
// | "/" | "[" | "]" | "?" | "="
// | "{" | "}" | SP | HT
// and redefined in RFC7230 as ...
// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
// token = 1*tchar
//
// This checks the input to make sure it's valid according to the
// http token rule. If the input doesn't match, it throws, if it
// does match, val is returned.
function checkIsHttpToken(val, label) {
if (!val || typeof val !== 'string')
return false;
for (var n = 0, l = val.length; n < l; n++) {
var c = val.charCodeAt(n);
if (c <= 32 || c == 34 ||
c == 44 || c == 47 ||
c == 123 || c == 125 ||
c == 40 || c == 41 ||
(c >= 58 && c <= 64) ||
(c >= 91 && c <= 93) ||
c >= 128)
throw new Error(
'Invalid character (' +
String.fromCharCode(c) +
') in HTTP ' + label + ' at position ' + (n + 1));
}
return val;
}
@nodejs/tsc ... thoughts?