使用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 关键执行步骤
-
empty():清空目标元素内容
- 移除所有子节点
- 清除关联事件监听器
- 返回当前上下文
-
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 关键差异点
- jQuery自动修正:会自动在
<option>外添加<select>标签 - 标签闭合优先级变化:由于添加了
<select>,导致HTML解析顺序改变 - 去除包装逻辑缺陷:使用
lastChild去除外层标签时处理不当
4.3 实际攻击向量
<option><style></option></select><abc></style></option>
- DOMPurify视角:视为无害HTML(示例A)
- jQuery视角:解析为有危害的HTML(示例B),最终导致XSS
5. 防御措施
-
DOMPurify配置:
- 启用针对jQuery的特殊处理配置
- 对
<style>标签内容中的<字符进行HTML实体转义
-
代码层面:
// 安全用法示例 var clean = DOMPurify.sanitize(dirty, {SAFE_FOR_JQUERY: true}); $(element).html(clean); -
其他防护:
- 避免直接使用
jQuery.fn.html()处理不可信输入 - 结合CSP策略提供额外防护层
- 避免直接使用
6. 影响范围
- 使用DOMPurify默认配置的jQuery应用
- 依赖客户端过滤的XSS防护方案
- 未正确处理HTML标签嵌套关系的场景
7. 技术总结
该漏洞本质上是由于jQuery对HTML的"修复"行为与标准解析器不一致,导致过滤器与最终渲染器对同一段HTML代码的安全评估出现差异。防御关键在于确保过滤器和渲染器使用相同的解析逻辑。