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 主要是由于 innerHTMLeval()document.write() 等方法 直接渲染用户输入数据,导致恶意代码执行。
  • 防御方式包括:使用 textContent,避免 eval(),过滤 javascript: 协议,启用 CSP
  • 具体绕过方式可以利用 HTML 标签、事件属性 (onerroronload)、字符串拼接等