Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f542e74

Browse filesBrowse files
bnoordhuisFishrock123
authored andcommitted
http: guard against response splitting in trailers
Commit 3c293ba ("http: protect against response splitting attacks") filters out newline characters from HTTP headers but forgot to apply the same logic to trailing HTTP headers, i.e., headers that come after the response body. This commit rectifies that. The expected security impact is low because approximately no one uses trailing headers. Some HTTP clients can't even parse them. PR-URL: #2945 Reviewed-By: Сковорода Никита Андреевич <chalkerx@gmail.com> Reviewed-By: Rod Vagg <r@va.gg>
1 parent 2084f52 commit f542e74
Copy full SHA for f542e74

File tree

Expand file treeCollapse file tree

2 files changed

+22
-9
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

2 files changed

+22
-9
lines changed
Open diff view settings
Collapse file

‎lib/_http_outgoing.js‎

Copy file name to clipboardExpand all lines: lib/_http_outgoing.js
+9-6Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -295,11 +295,7 @@ OutgoingMessage.prototype._storeHeader = function(firstLine, headers) {
295295
};
296296

297297
function storeHeader(self, state, field, value) {
298-
// Protect against response splitting. The if statement is there to
299-
// minimize the performance impact in the common case.
300-
if (/[\r\n]/.test(value))
301-
value = value.replace(/[\r\n]+[ \t]*/g, '');
302-
298+
value = escapeHeaderValue(value);
303299
state.messageHeader += field + ': ' + value + CRLF;
304300

305301
if (connectionExpression.test(field)) {
@@ -481,6 +477,13 @@ function connectionCorkNT(conn) {
481477
}
482478

483479

480+
function escapeHeaderValue(value) {
481+
// Protect against response splitting. The regex test is there to
482+
// minimize the performance impact in the common case.
483+
return /[\r\n]/.test(value) ? value.replace(/[\r\n]+[ \t]*/g, '') : value;
484+
}
485+
486+
484487
OutgoingMessage.prototype.addTrailers = function(headers) {
485488
this._trailer = '';
486489
var keys = Object.keys(headers);
@@ -496,7 +499,7 @@ OutgoingMessage.prototype.addTrailers = function(headers) {
496499
value = headers[key];
497500
}
498501

499-
this._trailer += field + ': ' + value + CRLF;
502+
this._trailer += field + ': ' + escapeHeaderValue(value) + CRLF;
500503
}
501504
};
502505

Collapse file

‎test/parallel/test-http-header-response-splitting.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-http-header-response-splitting.js
+13-3Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ var common = require('../common'),
44
http = require('http');
55

66
var testIndex = 0;
7-
const testCount = 4 * 6;
7+
const testCount = 2 * 4 * 6;
88
const responseBody = 'Hi mars!';
99

1010
var server = http.createServer(function(req, res) {
@@ -29,9 +29,15 @@ var server = http.createServer(function(req, res) {
2929
default:
3030
assert.fail('unreachable');
3131
}
32-
res.end(responseBody);
32+
res.write(responseBody);
33+
if (testIndex % 8 < 4) {
34+
res.addTrailers({ ta: header, tb: header });
35+
} else {
36+
res.addTrailers([['ta', header], ['tb', header]]);
37+
}
38+
res.end();
3339
}
34-
switch ((testIndex / 4) | 0) {
40+
switch ((testIndex / 8) | 0) {
3541
case 0:
3642
reply('foo \r\ninvalid: bar');
3743
break;
@@ -70,6 +76,10 @@ server.listen(common.PORT, common.mustCall(function() {
7076
res.on('data', function(s) { data += s; });
7177
res.on('end', common.mustCall(function() {
7278
assert.equal(data, responseBody);
79+
assert.strictEqual(res.trailers.ta, 'foo invalid: bar');
80+
assert.strictEqual(res.trailers.tb, 'foo invalid: bar');
81+
assert.strictEqual(res.trailers.foo, undefined);
82+
assert.strictEqual(res.trailers.invalid, undefined);
7383
}));
7484
res.resume();
7585
}));

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.