I am trying to create an iframe that has JS fire inside of it but does not have access to the parent document. The goal is to have a simple implementation and not include any special libraries. I found that the HTML5 Sandbox attribute is a viable solution; however, it is proving to be quite difficult to simultaneously sandbox an iframe and put JS inside of it.
I have tried:
- Adding JS to iframe and then sandboxing it from the parent document. This does not work because JS in iframe fires before the iframe sandbox is applied
- Creating iframe and setting HTML with
srcdoc
attribute (ex.<iframe sandbox="allow-scripts" srcdoc="<body><script src='sample1.js'></script><script src='sample2.js'></script></body>"></iframe>
) This does not work in IE according to here - Creating iframe and setting HTML with
src
attribute (ex.<iframe sandbox="allow-scripts" src="javascript:"<html><body><script src='sample1.js'></script><script src='sample2.js'></script></body></html>""></iframe
) This does not work in Firefox 38.0.5 (Mac OS X Yosemite) but works in Chrome 43 & Safari 8.0.4 ..."not working in Firefox" means that it will indeed allow sample2.js to add<span></span>
to the iframe DOM, but it does not set the innerText of the span; therefore, it does not work as intended. - Finally, I have just tried to dynamically create an iframe via JS. After adding the iframe to the DOM (without sandbox attribute), I write the HTML to it, which contains my scripts that I want to be sandboxed in the iframe. In the iframe head, I have a script to sandbox itself. Unfortunately, this does not seem to work. (Code below)
I created a JSFiddle, but it doesn't give the proper behavior because it is in a nested iframe... I set up a simple page and am testing on my localhost. Here is the code I am using for testing:
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
</head>
<body>
<!-- Case #2 ~ Does not work in IE -->
<iframe srcdoc="<body><script src='sample1.js'></script><script src='sample2.js'></script></body>" sandbox="allow-scripts">
</iframe>
<!-- Case #3 ~ Does not work in Firefox -->
<iframe src="javascript:"<html><body><script src='sample1.js'></script><script src='sample2.js'></script></body></html>"" sandbox="allow-scripts">
</iframe>
<!-- Case #4 ~ Sandbox maybe not applied? -->
<script>
var i = document.createElement('iframe');
i.src = "about:blank";
i.id = "bryce_iframe";
document.body.appendChild(i);
// iframe added to page
var j = document.getElementById('bryce_iframe').contentDocument;
j.open();
var js = "<html><head>" +
"<scr"+"ipt>window.top.document.getElementById('bryce_iframe').sandbox = 'allow-scripts';</scr"+"ipt>" +
"</head><body>" +
"<p>Hi</p>" +
"<scr"+"ipt>" +
"var p = document.createElement('p');" +
"p.innerText = 'should throw error'; console.log(p);" +
"window.top.document.body.appendChild(p);" +
"</scr"+"ipt>" +
"</body></html>";
// "window.top.document.body.appendChild(p)" should throw an error because of sandbox
j.write(js);
j.close();
</script>
</body>
</html>
My sample1.js file looks like this:
var s = document.createElement('span');
s.innerText = "hi";
window.top.document.body.appendChild(s);
My sample2.js file looks like this:
var txt = "this doesn't try to break out of iframe";
var s = document.createElement('span');
s.innerText = txt;
document.onload=document.body.appendChild(s);
I've been looking for helpful resources about this issue for weeks. It would be amazing to have another set of eyes looking into it with me.
I look forward to collaborating with whoever reaches out. Thank you in advance.
Just wondering why you are adding the
sandbox
attribute in your inner script in example #4?:The sandbox attribute should be added to the parent code:
This will prevent parent access.