将脚本标签代码附加到dom元素上执行,替代document.write
var str = '<script>alert(1)</script>';
var decoded = $("<div/>").html(str).text();
//document.write(decoded); THIS WORKS, but I want to avoid using document.write
var para = document.createElement("script");
var node = document.createTextNode(decoded);
para.appendChild(node);
var element = document.getElementById("div1");
element.appendChild(para);
问题是由于存在脚本标记,此 createElement 方法将不起作用。在编码的 str 中关闭脚本标记将导致语法错误 (Uncaught SyntaxError: Unexpected token '<')。 Document.write 运行完美,但我想避免使用它,因为它存在解析器块等缺点。
在实际使用情况下,编码的字符串将由用户输入一些广告。请注意,我们无法从他们输入的代码中删除脚本标签,而是使用 htmlentities($adcode) 将其保存在数据库中。
用户输入是可信的,因此不存在任何 xss 漏洞问题,而这些问题可能是由所提出的解决方案引起的。
示例用户输入之一:
<script async="async" src="someURL.js"></script>
<script>
var googletag = googletag || {};
googletag.cmd = googletag.cmd || [];
</script>
<div id="xyzid">
<script type="text/javascript">
googletag.cmd.push(function() {
googletag.pubads().display("Mobile_ATF_300x250", [300,250],"div-gpt-ad-0");
});
</script>
</div>
可能存在具有未知模式的各种不同版本的广告集。
其他不太相关的信息:我们将进一步使用类似
<script>
if(var==1) { codeblock1 } else { codeblock2}
</script>
的内容(此处 codeblock 是第一个代码块集)。因此,任何直接包含使用解码的用户输入的解决方案都将无用,因为脚本块将在 if-else 中中断。
因此,为了回答这个问题,我必须首先更改 ad2,因为它位于脚本标记内,而不再需要,您可以做的是创建一个名为 Script 的元素,类型为 text/javascript 并插入文本,然后将其插入正文中。
var ad2 = `alert(12)`;
var decoded = decodeHtml(ad2);
decoded = decoded.replace(/(<([^>]+)>)/ig,'')
var para = document.createElement("script");
para.type = "text/javascript";
para.text = decoded
var element = document.getElementById("div12")
element.appendChild(para)
这是 jsfiddle 中有关如何执行此操作的工作演示。
https://jsfiddle.net/59g24do1/
编辑 对于多个脚本,请改用此方法;我们在这里所做的是首先创建一个标签数组,然后使用前一个函数逐个创建,执行 for 循环以执行所有标签。 = >
function getParagraphs(htmlString) {
const div = document.createElement("div");
div.insertAdjacentHTML("beforeend", htmlString);
return Array.from(div.querySelectorAll("script"))
.map(script => script.outerHTML);
}
for(let i = 0;i<decoded.length;i++){
if(decoded[i].includes("src")){
let srcString = decoded[i].match('src="(.*)"')
var para = document.createElement("script");
let aux = decoded[i].replace(/(<([^>]+)>)/ig,'')
para.type = "text/javascript";
para.src = srcString[1]
para.text = aux
var element = document.getElementById("div12")
element.appendChild(para)
}else{
let aux = decoded[i].replace(/(<([^>]+)>)/ig,'')
let para = document.createElement("script");
para.type = "text/javascript";
para.text = aux
let element = document.getElementById("div12")
element.appendChild(para)
}
}
完整示例使用请见 jsfiddle https://jsfiddle.net/f2Leu74g/2/
我能够通过下面的代码解决这个问题,如果将来有人遇到同样的问题,我会更新它。
var ad = "whatever encoded here script code";
function decodeHtml(html) {
return $("<textarea/>").html(html).text();
}
function fetch(id, html) {
var elm = document.getElementById(id);
elm.innerHTML = html;
var scripts = elm.getElementsByTagName("script");
var scriptsClone = [];
for (var i = 0; i < scripts.length; i++) {
scriptsClone.push(scripts[i]);
}
for (var i = 0; i < scriptsClone.length; i++) {
var currentScript = scriptsClone[i];
var s = document.createElement("script");
// Copy all the attributes from the original script
for (var j = 0; j < currentScript.attributes.length; j++) {
var a = currentScript.attributes[j];
s.setAttribute(a.name, a.value);
}
s.appendChild(document.createTextNode(currentScript.innerHTML));
currentScript.parentNode.replaceChild(s, currentScript);
}
}
var decoded = decodeHtml(ad);
fetch('YourDivID',decoded);