使用jQuery绕过DOMPurify过滤器
字数 995 2025-08-26 22:11:35

jQuery绕过DOMPurify过滤器技术分析

1. 漏洞概述

本漏洞是由于jQuery的jQuery.fn.html()函数与标准document.innerHTML()函数在HTML渲染机制上的差异,导致在使用DOMPurify库默认配置时可能绕过XSS防护。官方文档已指出此问题。

2. 核心差异点

  • jQuery.fn.html():通过复杂处理流程渲染HTML,包含自动修正标签结构
  • document.innerHTML():直接按照标准HTML解析规则渲染

3. jQuery.html()函数执行流程分析

3.1 主函数入口

jQuery.fn.html: function(value) {
    return access(this, function(value) {
        var elem = this[0] || {};
        if (elem) {
            this.empty().append(value);
        }
    }, null, value, arguments.length);
}

3.2 关键执行步骤

  1. empty():清空目标元素内容

    • 移除所有子节点
    • 清除关联事件监听器
    • 返回当前上下文
  2. append():添加新内容

    • 调用domManip()处理DOM操作
    • 最终通过appendChild()添加元素

3.3 domManip函数

function domManip(collection, args, callback, ignored) {
    // 处理参数
    fragment = buildFragment(args, collection[0].ownerDocument, false, collection, ignored);
    // 执行回调添加节点
    callback.call(collection[i], node, i);
}

3.4 buildFragment函数(关键)

function buildFragment(elems, context, scripts, selection, ignored) {
    // 创建文档片段
    var fragment = context.createDocumentFragment();
    
    // 处理每个元素
    tmp = tmp || fragment.appendChild(context.createElement("div"));
    
    // 自动修正标签结构
    tag = (rtagName.exec(elem) || ["", ""])[1].toLowerCase();
    wrap = wrapMap[tag] || wrapMap._default;
    
    // 关键点:使用innerHTML渲染
    tmp.innerHTML = wrap[1] + jQuery.htmlPrefilter(elem) + wrap[2];
    
    // 去除外层包装
    j = wrap[0];
    while (j--) {
        tmp = tmp.lastChild;
    }
    
    // 返回处理后的片段
    return fragment;
}

4. 漏洞利用原理

4.1 解析差异示例

示例A(标准innerHTML):

document.getElementsByTagName("body")[0].innerHTML = 
    "<option><style></option></select><abc></style></option>";

示例B(jQuery处理后的等效代码):

document.getElementsByTagName("body")[0].innerHTML = 
    "<select><option><style></option></select><abc></style></option>";

4.2 关键差异点

  1. jQuery自动修正:会自动在<option>外添加<select>标签
  2. 标签闭合优先级变化:由于添加了<select>,导致HTML解析顺序改变
  3. 去除包装逻辑缺陷:使用lastChild去除外层标签时处理不当

4.3 实际攻击向量

<option><style></option></select><abc></style></option>
  • DOMPurify视角:视为无害HTML(示例A)
  • jQuery视角:解析为有危害的HTML(示例B),最终导致XSS

5. 防御措施

  1. DOMPurify配置

    • 启用针对jQuery的特殊处理配置
    • <style>标签内容中的<字符进行HTML实体转义
  2. 代码层面

    // 安全用法示例
    var clean = DOMPurify.sanitize(dirty, {SAFE_FOR_JQUERY: true});
    $(element).html(clean);
    
  3. 其他防护

    • 避免直接使用jQuery.fn.html()处理不可信输入
    • 结合CSP策略提供额外防护层

6. 影响范围

  • 使用DOMPurify默认配置的jQuery应用
  • 依赖客户端过滤的XSS防护方案
  • 未正确处理HTML标签嵌套关系的场景

7. 技术总结

该漏洞本质上是由于jQuery对HTML的"修复"行为与标准解析器不一致,导致过滤器与最终渲染器对同一段HTML代码的安全评估出现差异。防御关键在于确保过滤器和渲染器使用相同的解析逻辑。

jQuery绕过DOMPurify过滤器技术分析 1. 漏洞概述 本漏洞是由于jQuery的 jQuery.fn.html() 函数与标准 document.innerHTML() 函数在HTML渲染机制上的差异,导致在使用DOMPurify库默认配置时可能绕过XSS防护。官方文档已指出此问题。 2. 核心差异点 jQuery.fn.html() :通过复杂处理流程渲染HTML,包含自动修正标签结构 document.innerHTML() :直接按照标准HTML解析规则渲染 3. jQuery.html()函数执行流程分析 3.1 主函数入口 3.2 关键执行步骤 empty() :清空目标元素内容 移除所有子节点 清除关联事件监听器 返回当前上下文 append() :添加新内容 调用 domManip() 处理DOM操作 最终通过 appendChild() 添加元素 3.3 domManip函数 3.4 buildFragment函数(关键) 4. 漏洞利用原理 4.1 解析差异示例 示例A(标准innerHTML): 示例B(jQuery处理后的等效代码): 4.2 关键差异点 jQuery自动修正 :会自动在 <option> 外添加 <select> 标签 标签闭合优先级变化 :由于添加了 <select> ,导致HTML解析顺序改变 去除包装逻辑缺陷 :使用 lastChild 去除外层标签时处理不当 4.3 实际攻击向量 DOMPurify视角 :视为无害HTML(示例A) jQuery视角 :解析为有危害的HTML(示例B),最终导致XSS 5. 防御措施 DOMPurify配置 : 启用针对jQuery的特殊处理配置 对 <style> 标签内容中的 < 字符进行HTML实体转义 代码层面 : 其他防护 : 避免直接使用 jQuery.fn.html() 处理不可信输入 结合CSP策略提供额外防护层 6. 影响范围 使用DOMPurify默认配置的jQuery应用 依赖客户端过滤的XSS防护方案 未正确处理HTML标签嵌套关系的场景 7. 技术总结 该漏洞本质上是由于jQuery对HTML的"修复"行为与标准解析器不一致,导致过滤器与最终渲染器对同一段HTML代码的安全评估出现差异。防御关键在于确保过滤器和渲染器使用相同的解析逻辑。