dompurify.sanitize() 默认配置不安全,会放过onerror、javascript:等危险属性和协议,必须显式配置forbid_tags、allowed_uri_regexp等;前端净化可被绕过,真正可信的净化点仅在服务端入库前。

DOMPurify.sanitize() 为什么不能直接套用默认配置
默认配置会放过大量危险属性和协议,比如 onerror、javascript:、data:,甚至部分 SVG 标签。它只做基础标签白名单(p、strong、ul 等),但没禁用事件处理器或危险 URI scheme。
实际使用必须显式配置:
FORBID_TAGS: ['script', 'iframe', 'object', 'embed', 'base']-
ALLOWED_URI_REGEXP: /^https?:\/\//i(比ALLOWED_SCHEMES更可靠) -
KEEP_CONTENT: false(避免保留被删标签里的文本,防止语义绕过) - 对
a标签的href和img的src单独校验:DOMPurify.isValidAttribute('a', 'href', value)
前端调用 sanitize 后仍被 XSS 攻击?你漏掉了关键环节
DOMPurify 只在浏览器端运行,而攻击者根本不会触发它——禁用 JS、用 curl 直 POST、改 Form 表单 action,都能绕过所有前端逻辑。此时你看到的“已净化”只是假象。
真正可信的净化点只有一个:服务端入库前。PHP 必须用 HTMLPurifier 或 XssHtml,Node.js 推荐 sanitize-html(配 allowedTags + allowedAttributes + protocols),Java 用 Jsoup 的 Whitelist 模式。
常见错误:
- 只在前端跑
DOMPurify.sanitize(),后端直接INSERT INTO ... VALUES (?) - 后端用
strip_tags()或htmlspecialchars()处理富文本——前者不清理属性,后者把整个 HTML 当纯文本转义 - 渲染时用
v-html(Vue)或dangerouslySetInnerHTML(React)绑定未二次净化的字段
富文本字段入库前要双重净化,不是“一次就够了”
用户提交的原始 HTML 可能含畸形结构(如未闭合标签、嵌套错乱),DOMPurify 默认会尝试修复,但修复行为不可控;服务端库如 HTMLPurifier 也默认启用修复,但可能引入意外样式或布局偏移。
建议流程:
- 前端提交原始 HTML(不做净化,保留用户意图)
- 后端先用
DOMPurify.sanitize()做轻量预处理(仅用于日志或调试,不入库) - 再用服务端库执行严格白名单净化,并开启
HTMLPurifier::CONFIG['HTML.SafeEmbed'] = false等显式关闭高危选项 - 入库值必须是服务端净化后的结果,且数据库字段类型设为
TEXT,不加额外转义
特别注意:style 属性默认全被清空,要保留 color、font-size 等,得在配置里显式放开 CSS.AllowedProperties,而不是靠“默认允许”。
渲染时的陷阱:v-html / innerHTML 不是安全出口
即使你刚用 DOMPurify 处理过内容,只要变量来源不可信(比如从 API 返回、localStorage 读取、URL 参数解析),就绝不能直接塞进 v-html 或 element.innerHTML。
正确做法:
- 后端返回的 HTML 字段,必须是经服务端净化后的最终值
- 前端拿到后,再用 DOMPurify 做一次轻量校验(非必须,但可拦截 CDN 缓存污染等边缘情况)
- 永远优先用
textContent渲染纯文本场景;富文本只在明确需要格式时才用v-html - 若用 React,
dangerouslySetInnerHTML的__html字段必须来自可信后端接口,且该接口响应体已通过服务端净化
最易忽略的一点:富文本字段如果参与搜索、导出 PDF、生成邮件模板等下游流程,这些环节往往跳过前端净化逻辑,直接拼接 HTML —— 此时服务端净化的完整性就是唯一防线。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











