Escape strings in HTML output (XSS fix)

Modify the template producing HTML error responses to correctly
escape all strings that are possibly coming from the client making the
request. Before this change, the error responses were vulnerable to XSS
(cross-site scripting) attacks.
This commit is contained in:
Zachery Metcalf 2018-01-17 14:03:03 -07:00 committed by Miroslav Bajtoš
parent 4c69370751
commit 35328be26b
No known key found for this signature in database
GPG Key ID: 6F2304BA9361C7E3
4 changed files with 47 additions and 5 deletions

1
.npmrc Normal file
View File

@ -0,0 +1 @@
package-lock=false

View File

@ -19,7 +19,7 @@
"dependencies": {
"accepts": "^1.3.3",
"debug": "^2.2.0",
"ejs": "^2.4.2",
"ejs": "^2.5.7",
"http-status": "^1.0.0",
"js2xmlparser": "^3.0.0",
"strong-globalize": "^3.1.0"

View File

@ -472,6 +472,47 @@ describe('strong-error-handler', function() {
done);
});
it('HTML-escapes all 4xx response properties in production mode',
function(done) {
const error = new ErrorWithProps({
name: 'Error<img onerror=alert(1) src=a>',
message:
'No instance with id <img onerror=alert(1) src=a> found for Model',
statusCode: 404,
});
givenErrorHandlerForError(error, {debug: false});
requestHTML()
.end(function(err, res) {
expect(res.statusCode).to.eql(404);
const body = res.error.text;
expect(body).to.match(
/<title>Error&lt;img onerror=alert\(1\) src=a&gt;<\/title>/
);
expect(body).to.match(
/with id &lt;img onerror=alert\(1\) src=a&gt; found for Model/
);
done();
});
}
);
it('HTML-escapes all 5xx response properties in development mode',
function(done) {
const error = new ErrorWithProps({
message: 'a test error message<img onerror=alert(1) src=a>',
});
error.statusCode = 500;
givenErrorHandlerForError(error, {debug: true});
requestHTML()
.expect(500)
.expect(/<title>ErrorWithProps<\/title>/)
.expect(
/500(.*?)a test error message&lt;img onerror=alert\(1\) src=a&gt;/,
done
);
}
);
it('contains subset of properties when status=4xx', function(done) {
var error = new ErrorWithProps({
name: 'ValidationError',

View File

@ -1,19 +1,19 @@
<html>
<head>
<meta charset='utf-8'>
<title><%- data.name || data.message %></title>
<title><%= data.name || data.message %></title>
<style><%- include style.css %></style>
</head>
<body>
<div id="wrapper">
<h1><%- data.name %></h1>
<h2><em><%- data.statusCode %></em> <%- data.message %></h2>
<h1><%= data.name %></h1>
<h2><em><%= data.statusCode %></em> <%= data.message %></h2>
<%
// display all the non-standard properties
var standardProps = ['name', 'statusCode', 'message', 'stack'];
for (var prop in data) {
if (standardProps.indexOf(prop) == -1 && data[prop]) { %>
<div><b><%- prop %></b>: <%- data[prop] %></div>
<div><b><%= prop %></b>: <%= data[prop] %></div>
<% }
}
if (data.stack) { %>