dompurify 必须通过 javascript 调用 sanitize() 实现前端实时净化,而非正则硬删;它基于真实 dom 解析与白名单重建,可防御嵌套、编码混淆及大小写绕过等 xss 手段,但需显式配置 allowed_tags/attr、限制 uri 协议、禁用 style/class,并配合后端二次净化。

用 DOMPurify 做前端实时净化,而不是靠正则硬删
DOMPurify 是目前最可靠、被大量生产环境验证的 HTML 净化库,它不是简单地用 replace() 删掉 <script></script> 标签,而是完整解析 DOM 树,再按白名单策略重建安全节点。正则表达式在处理嵌套、换行、编码混淆(如 <script></script>)、大小写混写(<script></script>)时极易失效,而 DOMPurify 内置了对这些绕过手法的防御。
典型误用是只调用 DOMPurify.sanitize(html) 就完事——这默认只保留极简标签(<b></b>、<i></i> 等),但如果你需要支持 <img src> 或 <a href></a>,必须显式配置白名单:
const clean = DOMPurify.sanitize(dirtyHtml, {
ALLOWED_TAGS: ['b', 'i', 'u', 'p', 'br', 'img', 'a'],
ALLOWED_ATTR: ['src', 'href', 'alt', 'title'],
FORBID_TAGS: ['script', 'iframe', 'frame', 'frameset'],
FORBID_ATTR: ['onerror', 'onclick', 'onload', 'javascript:', 'data:text/html']
});
-
FORBID_TAGS和FORBID_ATTR是双重保险,即使某属性意外出现在允许标签里也会被剔除 - 不建议用
ADD_TAGS或ADD_ATTR扩展,容易引入未知风险;宁可收紧,也不要放宽 - 若需支持
<svg></svg>,必须额外启用SAFE_FOR_TEMPLATES: true,否则内联onload可能逃逸
服务端必须做二次校验,不能信任前端净化结果
前端净化可被绕过:用户禁用 JS、篡改 DOMPurify 配置、或直接发 POST 请求绕过前端逻辑。服务端必须独立执行等效净化,且不能复用同一份代码逻辑(避免单点失效)。
Java 场景下推荐用 jsoup 的 Cleaner + 自定义 Whitelist,而非正则替换:
- 错误做法:
html.replaceAll("<script>]*>[\s\S]*?</script>", "")—— 对注释中包裹的 script、CDATA 区块、或<script></script>大写变体无效 - 正确做法:用
Jsoup.parse(html).body().html()先解析,再用Cleaner按白名单过滤,最后输出 - 关键配置项:
Whitelist.relaxed()过于宽松,应基于业务最小集构造白名单,例如仅允许img[src]而非全部img[*]
静态分析要覆盖上下文敏感的危险模式
单纯移除 <script></script> 标签远远不够。真正的风险藏在属性值、URL 协议、CSS 表达式等上下文中,静态分析工具必须能识别这些隐式执行路径。
以下模式必须被拦截(哪怕它们不包含 <script></script>):
-
<a href="javascript:alert(1)"></a>——javascript:协议 -
<img src="x" onerror="alert(1)">—— 内联事件处理器 <div style="background:url('javascript:alert(1)')"> —— CSS 中的 JS 执行 <li> <code><iframe src="data:text/html,<script>...</script>"></iframe>—— data URI 注入-
<iframe sandbox="allow-scripts allow-same-origin" srcdoc="..."></iframe>—— 必须去掉allow-scripts,否则净化形同虚设 -
<iframe sandbox="allow-scripts" ...></iframe>是高危配置,等价于放弃防护 - CSP 应设为
Content-Security-Policy: default-src 'none'; script-src 'none'; object-src 'none',禁止任何脚本加载和执行 - 不要依赖
srcdoc的“看似隔离”——它仍共享父页面 origin,必须配合 sandbox 和 CSP 才真正隔离
DOMPurify 默认已覆盖前三种,但对 data: URI 的拦截需开启 ALLOW_DATA_ATTR: false(默认为 true),否则可能漏掉 iframe 或 img 的 data URL 载入。
沙箱 iframe + CSP 是运行时兜底,不是替代净化
即便完成前端+服务端双重净化,仍需在实际运行 HTML 的 iframe 上加硬性限制,因为净化无法 100% 覆盖所有浏览器解析差异或新发现的 bypass 技巧。
关键配置缺一不可:
复杂点在于:sandbox 属性会同时禁用 document.cookie 和 localStorage,如果在线编辑器本身依赖这些 API,需通过 postMessage 显式授权有限通信,而不是开放全部权限。











