I have a parent page that has a Content Security Policy on it. The main purpose of CSP is not to prevent XSS, but to prevent network access. This page has to run some user generated/submitted HTML/CSS/JS. I am running this user content in an iframe by using document.write to write the user content into this iframe.
NOTE: The user content that I have is not uploaded or present on a server but is available dynamically - say using some form.
I also want the user content to inherit the CSP of the parent page and any iframes created by the child iframe as well.
The policy applied on iframes according to the spec:
The policy of the embedding resource controls what may be embedded. The embedded resource, however, is controlled by the policy delivered with the resource, or the policy of the embedding resource if the embedded resource is a globally unique identifier (or a srcdoc frame).
So, the standard says that the policy will not be inherited, because the parent page is not a globally unique identifier. I don't want to use srcdoc iframe because of the following reasons
- The html can be very large
- The html needs to be escaped to use srcdoc which seems unreliable and unclean.
- Browser Support (Edge - under consideration)
But there is a twist:
When I went on to test this inheritance thing on browsers, the csp was actually being inherited on Chrome, Safari, Firefox but not Edge. This to me seems quite logical and correct.
Here is the sample test I performed:
<html>
<head>
<!-- CSP just for demo purposes - not the actual csp -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'unsafe-inline'; style-src 'unsafe-inline'"/>
</head>
<body>
<h1>Parent Content</h1>
<p style="font-weight: bold; font-family: arial, sans-serif;">
The image here will be blocked due to CSP (default-src directive).
However the iframe's image will not be blocked on Edge since the CSP is not inherited.
</p>
<img src="http://www.w3schools.com/html/pic_mountain.jpg"/>
<script>
window.addEventListener("DOMContentLoaded", function() {
// creating the child iframe
// Some user controlled HTML content.
var html = "<html><body><h1>Child Content</h1><img src='http://www.w3schools.com/html/pic_mountain.jpg'/></body></html>";
var iframe = document.createElement("iframe");
iframe.setAttribute("height", "400px");
iframe.setAttribute("width", "400px");
document.body.appendChild(iframe); //need to append first to be able to write into the iframe.
var iframeDoc = iframe.contentWindow.document;
iframeDoc.open();
iframeDoc.write(html);
iframeDoc.close();
});
</script>
</body>
</html>
So, finally my questions are:
- Can I depend on this inheritance of CSP to child iframe on Chrome, Firefox, and Safari? - I can't find this documented anywhere.
- Is there a clean and reliable way to be able to use srcdoc with escaping and everything? What are the performance impacts of using srcdoc?
- Is there any other method to do this?
More thought:
The spec's (and Edge) handling of CSP applying to the iframe further adds to the risk of allowing 'unsafe-inline' for scripts to prevent XSS. Because then the attacker can even use document.write like this to trigger creation of iframe to his own malicious site even. Even child-src/frame-src 'none', doesn't stop creation of iframe using document.write. Isn't this very bad for security?