在使用 .innerHTML、.outerHTML、document.write() 时要特别小心,不要把不可信的数据作为 HTML 插到页面上,而应尽量使用 .textContent、.setAttribute() 等。
如果用 Vue/React 技术栈,并且不使用 v-html/dangerouslySetInnerHTML 功能,就在前端 render 阶段避免 innerHTML、outerHTML 的 XSS 隐患。
DOM 中的内联事件监听器,如 location、onclick、onerror、onload、onmouseover 等,` 标签的href属性,JavaScript 的eval()、setTimeout()、setInterval()` 等,都能把字符串作为代码运行。如果不可信的数据拼接到字符串中传递给这些 API,很容易产生安全隐患,请务必避免。
<!-- 内联事件监听器中包含恶意代码 --><img onerror="http://www.likecs.com/UNTRUSTED" src="http://www.likecs.com/data:image/png,">
<!-- 链接内包含恶意代码 -->
<a href="http://www.likecs.com/UNTRUSTED">1</a>
<script>
// setTimeout()/setInterval() 中调用恶意代码
setTimeout("http://www.likecs.com/UNTRUSTED")
setInterval("http://www.likecs.com/UNTRUSTED")
// location 调用恶意代码
location.href = \'UNTRUSTED\'
// eval() 中调用恶意代码
eval("http://www.likecs.com/UNTRUSTED")
</script>
如果项目中有用到这些的话,一定要避免在字符串中拼接不可信数据。
其他 XSS 防范措施虽然在渲染页面和执行 JavaScript 时,通过谨慎的转义可以防止 XSS 的发生,但完全依靠开发的谨慎仍然是不够的。以下介绍一些通用的方案,可以降低 XSS 带来的风险和后果。
Content Security Policy严格的 CSP 在 XSS 的防范中可以起到以下的作用:
禁止加载外域代码,防止复杂的攻击逻辑。
禁止外域提交,网站被攻击后,用户的数据不会泄露到外域。
禁止内联脚本执行(规则较严格,目前发现 GitHub 使用)。
禁止未授权的脚本执行(新特性,Google Map 移动版在使用)。
合理使用上报可以及时发现 XSS,利于尽快修复问题。
关于 CSP 的详情,请关注前端安全系列后续的文章。
输入内容长度控制对于不受信任的输入,都应该限定一个合理的长度。虽然无法完全防止 XSS 发生,但可以增加 XSS 攻击的难度。
其他安全措施
HTTP-only Cookie: 禁止 JavaScript 读取某些敏感 Cookie,攻击者完成 XSS 注入后也无法窃取此 Cookie。
验证码:防止脚本冒充用户提交危险操作。
XSS 的检测