XSS 之 JS 输出(XSS via JavaScript Output)
JS 输出型 XSS 指的是当用户输入的内容被 JavaScript 代码处理并输出到页面上时,如果没有正确进行转义或过滤,就可能导致 XSS 漏洞。
1. JS 输出型 XSS 产生的场景
如果网站使用 JavaScript 直接在前端操作 DOM 来输出用户输入的数据,而没有进行适当的转义,就可能出现 XSS。例如:
(1) innerHTML
造成的 XSS
document.getElementById("demo").innerHTML = userInput;
假设 userInput
为:
<script>alert('XSS')</script>
浏览器解析 innerHTML
时会执行 <script>
,导致 XSS。
绕过示例
如果网站过滤了 <script>
,可以尝试:
<img src="x" onerror="alert('XSS')">
或者:
<svg onload=alert('XSS')></svg>
(2) document.write()
造成的 XSS
如果 JavaScript 代码直接写入用户输入:
document.write(userInput);
那么如果 userInput
是:
<script>alert('XSS')</script>
就会导致 XSS。
(3) eval()
造成的 XSS
如果网站使用 eval()
处理用户输入:
eval(userInput);
那么输入:
alert('XSS')
会直接执行。
更高级的绕过
有时网站可能会拼接字符串,例如:
eval("console.log('" + userInput + "')");
如果输入:
');alert('XSS');//
那么 eval()
解析后会变成:
console.log('');alert('XSS');//')
成功执行 XSS。
(4) setTimeout()
和 setInterval()
如果网站使用:
setTimeout(userInput, 1000);
输入:
alert('XSS')
就会在 1 秒后执行。
(5) location.href
造成的 XSS
如果网站代码如下:
document.location.href = userInput;
那么输入:
javascript:alert('XSS')
就会执行 XSS。
2. 如何防御 JS 输出 XSS
(1) 使用 textContent
而非 innerHTML
document.getElementById("demo").textContent = userInput;
这样即使 userInput
包含 <script>
,也不会被解析。
(2) 过滤 javascript:
协议
如果 location.href
可能受到用户输入影响,应过滤:
if (userInput.startsWith("javascript:")) {
userInput = "about:blank";
}
(3) 采用 CSP (Content Security Policy)
设置 Content-Security-Policy
:
Content-Security-Policy: default-src 'self'; script-src 'self'
这样即使 XSS 存在,也不会执行。
总结
- JS 输出型 XSS 主要是由于
innerHTML
、eval()
、document.write()
等方法 直接渲染用户输入数据,导致恶意代码执行。 - 防御方式包括:使用
textContent
,避免eval()
,过滤javascript:
协议,启用 CSP。 - 具体绕过方式可以利用 HTML 标签、事件属性 (
onerror
、onload
)、字符串拼接等。