I have an iframe:
<iframe id="msgContainer" sandbox="allow-same-origin"></iframe>
and I'd like to insert HTML into it, but not let any JavaScript that may be contained in the HTML run (this includes both <script>
tags and on*
attributes. I know how to insert HTML (just use document.getElementById('msgContainer').contentDocument.body.innerHTML=myHTML
but I'd like to prevent any JS in myHTML
from running. The way I've tried to do this is by using the sandbox
attribute and only allowing same-origin, but JS still runs. Is there any way to do this?
Thanks
I couldn't find any answer other than to parse out the JS from an html string inserted into the iframe. Here's my code (if it helps anyone else):
/** Removes javascript from html string
* html: the string to be cleaned
*/
function clean(html) {
function stripHTML(){
html = html.slice(0, strip) + html.slice(j);
j = strip;
strip = false;
}
var strip = false,
lastQuote = false,
tag = false;
const prefix = "ANYTHING",
sandbox = " sandbox=''";
for(var i=0; i<html.length; i++){
if(html[i] === "<" && html[i+1] && isValidTagChar(html[i+1])) {
i++;
tag = false;
/* Enter element */
for(var j=i; j<html.length; j++){
if(!lastQuote && html[j] === ">"){
if(strip) {
stripHTML();
}
/* sandbox iframes */
if(tag === "iframe"){
var index = html.slice(i, j).toLowerCase().indexOf("sandbox");
if(index > 0) {
html = html.slice(0, i+index) + prefix + html.slice(i+index);
j += prefix.length;
}
html = html.slice(0, j) + sandbox + html.slice(j);
j += sandbox.length;
}
i = j;
break;
}
if(!tag && html[j] === " "){
tag = html.slice(i, j).toLowerCase();
}
if(lastQuote === html[j]){
lastQuote = false;
continue;
}
if(!lastQuote && html[j-1] === "=" && (html[j] === "'" || html[j] === '"')){
lastQuote = html[j];
}
/* Find on statements */
if(!lastQuote && html[j-2] === " " && html[j-1] === "o" && html[j] === "n"){
strip = j-2;
}
if(strip && html[j] === " " && !lastQuote){
stripHTML();
}
}
}
}
html = stripScripts(html);
return html;
}
/** Returns whether or not the character is a valid first character in a tag
* str: the first character
*/
function isValidTagChar(str) {
return str.match(/[a-z?\\\/!]/i);
}
/** Strips scripts from a string of html
* html: the string of html to be stripped
*/
// NOTE: <script> tags won't run in this context
function stripScripts(html) {
var div = document.createElement('div');
div.innerHTML = html;
var scripts = div.getElementsByTagName('script');
var i = scripts.length;
while (i--) {
scripts[i].parentNode.removeChild(scripts[i]);
}
return div.innerHTML;
}