显示用户上传的html内容 - 安全问题

时间:2016-08-19 20:41:19

标签: javascript php html

我有一个功能,用户可以上传html文件然后通过PHP读取其内容并将其作为字符串发送到第三方API。在我将其发送到API之前,我想生成他们上传到用户的HTML的预览,以便他们可以按“确认”按钮发送它。

HTML文件应该主要是字母模板,但是用户可以在显示预览时修改html并添加一些脚本标签或注入可能损害我网站的其他恶意代码。有没有办法可以避免这种情况?

我考虑过剥离标签,但是如果他们在html元素中有onclick事件呢?

4 个答案:

答案 0 :(得分:2)

我从这样的东西开始剥离脚本和评论:

$htmlblacklist[] = '@<script[^>]*?>.*?</script>@si'; //bye bye javascript
$htmlblacklist[] = '@<![\s\S]*?--[ \t\n\r]*>@'; //goodbye comments

//now apply blacklist
$value = preg_replace($htmlblacklist, '', $value);

对于内联事件,您应该使用DOMDocument,因为它理解HTML而正则表达式在黑暗中拍摄。

实际上,你可以将DOMDocument用于所有这些,而根本不使用Regex。在DOMDocument对象中加载HTML,并遍历树,删除您想要的内容。

答案 1 :(得分:0)

不是100%这对你有用,但似乎将HTML作为SVG渲染到画布上会将内容限制在你的要求范围内(没有脚本,没有外部加载)。

请在此处查看更多文档:https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Drawing_DOM_objects_into_a_canvas

  

鉴于您的担忧,您可能想知道这是如何安全的   从画布中读取敏感数据的可能性。该   答案是这样的:这个解决方案依赖于这个事实   SVG图像的实现非常严格。 SVG图像不是   允许加载任何外部资源,例如,甚至是那些   似乎来自同一个域。光栅图像等资源   (例如JPEG图像)或s必须作为数据内联:URI。

     

此外,您不能在SVG图像中包含脚本,因此没有   从其他脚本和SVG中的DOM元素访问DOM的风险   图像无法接收输入事件,因此无法加载   将特权信息转换为表单控件(例如完整路径转换为表单控件)   文件元素)并渲染它,然后拉出那些信息   读取像素。

答案 2 :(得分:0)

我可能找到了处理此问题的库。尚未对其进行全面测试,但根据其描述可能是:http://htmlpurifier.org/

答案 3 :(得分:0)

使用FileReader读取文件内容,使用iframe安全(或不)查看文件:

document.querySelector("button").addEventListener(
    'click',
    function() {
      let iframe = document.createElement("iframe"),
        holder = document.querySelector("#iframeholder"),
        sandboxFlags = [
          ...document.querySelectorAll('.sandbox-flags:checked')
        ].map(_ => _.value).join(','),
        file = document.querySelector('input[type=file]').files[0],
        reader = new FileReader();


      reader.addEventListener("load", function() {
        iframe.setAttribute("scrolling", "no");
        iframe.setAttribute("frameborder", "0");
        iframe.setAttribute("srcdoc", this.result);
        /*
         * Sandboxing is not allowed in code snippets
         * iframe.setAttribute("sandbox", sandboxFlags);
         *
         */
        console.log(`sandbox=${sandboxFlags}`);

        while (holder.firstChild)
          holder.removeChild(holder.firstChild);

        holder.appendChild(iframe);
        
      }, false);

      reader.readAsText(file);
  },
  false);
label {
  display: block
}

#iframeholder>iframe {
  border:1px solid black;
  height:400px;
  width:400px;
}
<div>
  <input id="browse" type="file" >
</div>
  <label>
    <input type="checkbox" class="sandbox-flags" value='allow-script' />allow-scripts
  </label>
  <label>
    <input type="checkbox" class="sandbox-flags" value='allow-popups-to-escape-sandbox' />allow-popups-to-escape-sandbox
  </label>
  <label>
    <input type="checkbox" class="sandbox-flags" value='allow-forms' />allow-forms
  </label>
  <label>
    <input type="checkbox" class="sandbox-flags" value='allow-modals' />allow-modals
  </label>
<div>
  <button type="button">Preview</button>
</div>
<div id="iframeholder"></div>