将脚本标记代码附加到 dom 元素以执行,替代 document.write

Attach script tag code to dom element for execution , alternate for 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);

jsfiddle.net/1bz9mL7k/2

问题是由于存在脚本标记,此 createElement 方法将不起作用。在编码的 str 中关闭脚本标签将导致语法错误(未捕获的语法错误:意外的标记“<”)。 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);