I found many similar questions, but not one that would discuss this scenario.
app.get('/', function(req, res) {
res.set('Content-Type', 'text/html');
res.send(`<html>
<body>
Hello, World!
</body>
<script>
const test = ${JSON.stringify({html: '</script><script>alert(1)</script>'})};
</script>
</html>`);
});
This will produce HTML as follows:
<html>
<body>
Hello, World!
</body>
<script>
const test = {"html":"</script><script>alert(1)</script>"};
</script>
</html>
which as you can see, allows injection from JSON.
Here is a quick replit: https://stylishtrustysupercollider.gajus.repl.co/
Assuming that JSON contains arbitrary content that we have no control over, what is the correct way to handle this scenario?
Considering producing base64 encoded string but it feels like an overkill.
2
Answers
I am surprised this is necessary, but it appears that the answer is a variation of:
or to break it down...
JSON.stringify
<
and>
usingencodeURI
decodeURI
encodeURI
/decodeURI
could also be replaced with alternative encoding mechanisms.As pointed out by Quentin, this is not safe unless you explicitly wrap the output with
"
rather than'
. This seems like an easy mistake to make and not worth the risk.I took a quick glance at existing libraries for escaping/unescaping HTML and identified that it basically falls down to escaping
&
,<
,>
,'
and"
characters.The following code is taken from
html-escaper
:Using the latter approach/library is preferable over attempting to escape with
encodeURI
or similar approaches.<script>
element) part of documente.g.
server.js
views/index.ejs
You could replace step 1 with your own HTML escaping routines, but I generally prefer something tried and tested.