
DOM-based XSS 是一种由客户端脚本解析用户输入并执行的跨站脚本漏洞,核心是用户输入被直接插入到 DOM 树中,浏览器在解析 DOM 时触发恶意脚本,与反射型 XSS 的关键区别在于脚本执行由客户端而非服务器端触发。
同学们,先理解 DOM 是浏览器解析 HTML 后构建的树形结构,每个节点(如 div、按钮)都是可操作的对象。DOM-based XSS 的原理是:用户输入被当作脚本代码插入到 DOM 节点(比如事件监听器属性或直接插入节点内容),浏览器在处理这些节点时,会直接执行插入的脚本。简单类比:把 DOM 看作一个“脚本执行环境”,用户输入变成这个环境里的代码片段,浏览器启动这个环境,运行代码。具体来说,触发点通常包括:
onclick、onerror):直接将用户输入赋值为事件处理程序;src、href 的动态更新);innerHTML、textContent,其中 innerHTML 是典型,因为直接插入 HTML)。执行流程是:用户输入(如恶意脚本)通过 URL 参数或表单提交进入客户端;客户端脚本将输入插入 DOM 节点(比如 document.getElementById('content').innerHTML = userInput);浏览器解析 DOM 时,触发恶意脚本(如弹窗、窃取 cookie)。
| 特性/场景 | 反射型XSS | DOM-based XSS |
|---|---|---|
| 定义 | 用户输入被包含在服务器返回的 HTML 中,客户端接收后执行 | 用户输入被直接插入到 DOM 树中,浏览器解析 DOM 时执行 |
| 触发点 | 服务器端处理请求,返回包含输入的 HTML | 客户端脚本解析用户输入,修改 DOM 后执行(如事件监听器、动态属性赋值) |
| 依赖 | 服务器返回包含输入的页面 | 客户端脚本解析用户输入并修改 DOM |
| 使用场景 | 用户输入出现在页面中(如搜索结果、表单反馈) | 用户输入被插入到 DOM 节点(如事件处理、动态内容渲染,如按钮点击触发脚本) |
| 注意点 | 需要用户主动访问包含输入的页面 | 需要用户访问页面后,输入被 DOM 解析执行(不一定需要点击,客户端直接执行) |
假设一个网页有一个按钮,用户输入被赋值给按钮的 onclick 事件处理程序。用户输入:alert('hacked')。页面伪代码:
<button id="btn"></button>
<script>
const userInput = new URLSearchParams(window.location.search).get('cmd'); // URL 参数
document.getElementById('btn').onclick = userInput; // 事件监听器直接赋值用户输入
</script>
当用户访问 example.com/?cmd=alert('hacked') 时,浏览器解析 DOM,触发按钮的 onclick 事件,执行 alert('hacked') 脚本。
面试官您好,DOM-based XSS 核心是客户端脚本解析用户输入并执行。简单说,就是用户输入被直接插入 DOM 树,浏览器在解析 DOM 时触发恶意脚本。与反射型 XSS 区别在于,反射型是服务器返回时包含输入,客户端接收后执行;而 DOM-based 是客户端处理输入,修改 DOM 后执行。比如用户输入被插入到某个元素的 onclick 事件处理程序,浏览器直接执行。利用的话,构造恶意输入(如 <script>alert('hacked')</script>),用户访问页面后脚本被 DOM 解析执行。防御方面,主要是避免用事件监听器直接赋值用户输入(改用 DOM 文本节点插入),或者对用户输入进行 HTML 转义(比如用 textContent 替代 innerHTML),以及启用内容安全策略(CSP),限制脚本来源,防止外部脚本执行。
innerHTML 插入用户输入(改用 textContent 或 insertAdjacentText),以及内容安全策略(CSP)限制脚本执行。innerHTML 插入),导致客户端仍可利用。