I would like to simulate a server-side rendering XSS vulnerability. I have a simple node server that loads an HTML template and injects into it some data that has malicious content (a closing script tag and a new malicious script open and close tags with an alert inside). Here is the repo for this question.
Issue: when I open the index.html below, it fetches the template from the server, calls text()
method on the Response
, and then using the DOM API injects it as innerHTML into the body of the document. The alert is not displayed, and I think this has something to do with it not being ok to inject a script tag as innerHTML.
Here is simple node server:
const http = require("http");
const getTemplate = require("./template.js");
const server = http.createServer(function(req, res) {
const data = {
username: "</script><script>alert('d')</script>"
};
const payloadString = JSON.stringify(data);
console.log("Sending");
const template = getTemplate(data);
console.log(template);
res.setHeader("Content-Type", "text/html");
res.setHeader("Access-Control-Allow-Origin", "*");
res.writeHead(200);
res.end(template);
});
server.listen(3000, function() {
console.log("The server is listening on port " + 3000);
});
An HTML template:
const getTemplate = data => `
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div>
</div>
<script>
window.data = ${JSON.stringify(data)}
</script>
</body>
</html>
`;
module.exports = getTemplate;
And finally, the index.html to open in the browser:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<script type="text/javascript">
fetch("http://localhost:3000")
.then(r => r.text())
.then(r => {
console.log(r);
const root = document.body;
root.innerHTML = r;
});
</script>
</body>
</html>
What do I need to do here to actually simulate how a real app would mistakenly render the malicious script?
If I wanted to get the script to actually run I believe I could convert it to HTML somehow, but I don't think this is what a real app would do.
EDIT: PARTIAL ANSWER
To simulate the SSR, don't use the index.html
file to inject the template requested from the server. SSR would actually be directly making this request in the browser and rendering the template directly. This set up executes the malicious script tag, because the HTML is processed by the browser and it now contains the malicious script tag, so we see the alert pop up.
In the case of directly opening the index.html
file, a request is made, the template is obtained and injected into the body
using innerHTML
, but this happens after the DOM content has been loaded, so the injection injects the script tag but it doesn't get executed. Is this a correct interpretation?