基于DOM的XSS漏洞与防护
字数 1306 2025-11-22 16:37:31

基于DOM的XSS漏洞与防护

1. 漏洞描述

基于DOM的XSS(跨站脚本)是一种客户端漏洞,攻击者通过操纵页面的DOM(文档对象模型)环境来注入恶意脚本。与反射型或存储型XSS不同,DOM型XSS的恶意代码无需经过服务器响应,而是直接在浏览器中通过修改DOM结构(如document.locationdocument.write等)触发。

关键特征

  • 攻击载荷在URL参数或客户端存储(如localStorage)中传递,但不会被发送到服务器。
  • 漏洞触发依赖于前端JavaScript对用户输入的不安全处理。

2. 漏洞原理与触发场景

2.1 典型触发流程

  1. 用户访问恶意构造的URL(例如:http://example.com/page#<script>alert(1)</script>)。
  2. 页面JavaScript从URL片段(location.hash)或参数(location.search)中读取数据。
  3. 数据未经净化直接被插入DOM(如通过innerHTMLdocument.write)。
  4. 恶意脚本在受害者浏览器中执行。

2.2 常见危险代码模式

// 示例1:直接使用location.hash  
const userInput = location.hash.substring(1);  
document.getElementById("content").innerHTML = userInput; // 危险!  

// 示例2:通过URL参数动态生成内容  
const urlParams = new URLSearchParams(location.search);  
document.write(urlParams.get("keyword")); // 危险!  

3. 漏洞挖掘与验证

3.1 识别数据源

  • URL参数location.searchlocation.hashdocument.referrer
  • 客户端存储localStoragesessionStorage、Cookie。
  • 全局变量:通过window.name或postMessage传递的数据。

3.2 测试方法

  1. 在参数中插入测试载荷(如<img src=x onerror=alert(1)>)。
  2. 观察页面是否弹窗或DOM是否被修改(使用开发者工具检查元素)。
  3. 确认输入是否被编码或过滤:
    • <被转义为&lt;,则漏洞不存在;
    • 若原始载荷被直接插入DOM,则漏洞存在。

4. 漏洞防护方案

4.1 输入验证与编码

  • 避免直接操作HTML:使用textContent代替innerHTML,避免将用户输入作为HTML解析。
  • 上下文感知编码
    • 插入到HTML属性时,使用setAttribute或编码特殊字符(如"&quot;)。
    • 插入到URL时,使用encodeURIComponent
  • 推荐使用安全库(如DOMPurify)对HTML进行净化:
    const cleanInput = DOMPurify.sanitize(userInput);  
    document.getElementById("content").innerHTML = cleanInput;  
    

4.2 安全API与策略

  • 禁用危险函数:避免使用eval()document.write()innerHTML等。
  • 实施内容安全策略(CSP):通过HTTP头禁止内联脚本执行:
    Content-Security-Policy: script-src 'self'; object-src 'none';  
    

4.3 设计层面防护

  • 最小化DOM操作:将动态数据与代码逻辑分离(如使用前端框架的模板引擎)。
  • 严格定义数据源:仅允许可信来源(如服务器渲染的数据)修改DOM。

5. 实战案例:修复漏洞代码

漏洞代码

// 从URL片段中获取数据并直接插入页面  
const data = decodeURIComponent(location.hash.slice(1));  
document.querySelector("#status").innerHTML = data;  

修复后代码

// 使用textContent避免HTML解析  
const data = decodeURIComponent(location.hash.slice(1));  
document.querySelector("#status").textContent = data;  

// 或使用DOMPurify净化  
const cleanData = DOMPurify.sanitize(data);  
document.querySelector("#status").innerHTML = cleanData;  

6. 总结

DOM型XSS的防护核心是严格区分数据与代码。通过前端安全编码规范、自动化工具(如CSP、静态检查)以及框架的内置防护机制,可有效降低风险。

基于DOM的XSS漏洞与防护 1. 漏洞描述 基于DOM的XSS(跨站脚本)是一种客户端漏洞,攻击者通过操纵页面的DOM(文档对象模型)环境来注入恶意脚本。与反射型或存储型XSS不同,DOM型XSS的恶意代码无需经过服务器响应,而是直接在浏览器中通过修改DOM结构(如 document.location 、 document.write 等)触发。 关键特征 : 攻击载荷在URL参数或客户端存储(如 localStorage )中传递,但不会被发送到服务器。 漏洞触发依赖于前端JavaScript对用户输入的不安全处理。 2. 漏洞原理与触发场景 2.1 典型触发流程 用户访问恶意构造的URL(例如: http://example.com/page#<script>alert(1)</script> )。 页面JavaScript从URL片段( location.hash )或参数( location.search )中读取数据。 数据未经净化直接被插入DOM(如通过 innerHTML 或 document.write )。 恶意脚本在受害者浏览器中执行。 2.2 常见危险代码模式 3. 漏洞挖掘与验证 3.1 识别数据源 URL参数 : location.search 、 location.hash 、 document.referrer 。 客户端存储 : localStorage 、 sessionStorage 、Cookie。 全局变量 :通过 window.name 或postMessage传递的数据。 3.2 测试方法 在参数中插入测试载荷(如 <img src=x onerror=alert(1)> )。 观察页面是否弹窗或DOM是否被修改(使用开发者工具检查元素)。 确认输入是否被编码或过滤: 若 < 被转义为 &lt; ,则漏洞不存在; 若原始载荷被直接插入DOM,则漏洞存在。 4. 漏洞防护方案 4.1 输入验证与编码 避免直接操作HTML :使用 textContent 代替 innerHTML ,避免将用户输入作为HTML解析。 上下文感知编码 : 插入到HTML属性时,使用 setAttribute 或编码特殊字符(如 " → &quot; )。 插入到URL时,使用 encodeURIComponent 。 推荐使用安全库(如DOMPurify)对HTML进行净化: 4.2 安全API与策略 禁用危险函数:避免使用 eval() 、 document.write() 、 innerHTML 等。 实施内容安全策略(CSP):通过HTTP头禁止内联脚本执行: 4.3 设计层面防护 最小化DOM操作:将动态数据与代码逻辑分离(如使用前端框架的模板引擎)。 严格定义数据源:仅允许可信来源(如服务器渲染的数据)修改DOM。 5. 实战案例:修复漏洞代码 漏洞代码 : 修复后代码 : 6. 总结 DOM型XSS的防护核心是 严格区分数据与代码 。通过前端安全编码规范、自动化工具(如CSP、静态检查)以及框架的内置防护机制,可有效降低风险。