innerHTML 的漏洞与安防
2019-08-02 本文已影响0人
wfatec
innerHTML的漏洞
早期的前端开发人员在写代码时通常会用到 element.innerHTML()
方法,实际上这个方法是存在很大漏洞的,来看下面一个例子:
var element = document.getElementById("root");
element.innerHTML = '<script>alert("XSS Attack");</script>';
看到这里似乎完成了一个简单的 XSS 攻击。执行一下,发现什么都没有发生 😂。事实上,内建的安全机制已经将传入的 DOM 进行了解析并执行。这里我查阅了一下文档,里面有这样一段话:
HTML 5 中指定不执行由 innerHTML 插入的
<script>
标签。然而,有很多不依赖<script>
标签去执行 JavaScript 的方式。所以当你使用 innerHTML 去设置你无法控制的字符串时,这仍然是一个安全问题。例如:
var element = document.getElementById("root");
element.innerHTML = "<img src=x onerror=\"alert('XSS Attack')\">";
此时,我们注入的脚本还是被执行了。
安防方案
- 使用
textContent
element.textContent = "<img src=x onerror=\"alert('XSS Attack')\">";
此时,我们会将 <img src=x onerror="alert(\'XSS Attack\')">
以字符串的形式来存取,因而可以避免执行脚本.
- 对待传入 DOM 的内容进行净化
虽然 textContent
能解决一部分问题,但是并不能解决所有问题,当我们需要添加额外的标记时,还是需要使用 innerHTML
的。例如:
element.innerHTML = "<h1>" + yourString + "</h1>";
这个时候,我们只能选择对 yourString
进行净化:
var sanitizeHTML = function(str) {
var temp = document.createElement("div");
temp.textContent = str;
return temp.innerHTML;
};
通过创建一个临时的 div
并通过 textContent
存入内容,从而将特殊字符进行转译,然后再通过 innerHTML
返回这些转译过的内容,这是因为 innerHTML
可以阻止转译后的字符被转换回未转译的状态。
var div = document.getElementById("root");
div.innerHTML =
"<h1>" +
sanitizeHTML("<img src=x onerror=\"alert('XSS Attack')\">") +
"</h1>";
这是一种更为通用的做法。
参考
Preventing cross-site scripting attacks when using innerHTML in vanilla JavaScript