必须在内容渲染前净化,而非仅保存时一次;否则加载时直接执行恶意代码。主流编辑器不阻止onerror等事件属性,也不过滤javascript:协议或style表达式,专注格式正确性而非安全边界。dompurify需在提交保存前和渲染前两次调用,形成闭环,并注意ssr配置、白名单控制、框架中正确封装及url协议后端校验。

必须在内容渲染前净化,而不是只在保存时做一次;否则加载时直接执行恶意代码。
为什么不能只靠编辑器自带过滤
主流编辑器(如 Quill、TinyMCE、CKEditor)默认不阻止 onerror、onclick 等事件属性,也不过滤 javascript: 协议链接或内联 style 中的表达式。它们专注格式正确性,而非安全边界。
常见错误现象包括:
- 用户粘贴含
<img src="x" onerror="fetch('/steal?c='+document.cookie)">的 HTML,编辑器照收不误 - 富文本“源码模式”下手动输入
@#@#@#@#@#@#@#@#@#@0,后端未净化就存库 - 前端用
v-html或innerHTML直接渲染服务端返回的原始 HTML 字段,触发 XSS
DOMPurify 必须在两个环节调用
单次净化无法覆盖所有攻击路径。必须形成闭环:提交时净化 + 渲染前再次净化。
- 提交保存前:调用
DOMPurify.sanitize(dirtyHTML)处理用户输入,再发给后端 - 页面加载时:即使数据库里存的是“已净化”内容,也要在插入 DOM 前再过一遍
DOMPurify.sanitize()—— 防止存储层被绕过或污染 - 若使用 SSR(如 Nuxt),Node.js 环境需额外配置
DOMPurify.setConfig({RETURN_DOM: false}),避免依赖浏览器 DOM API 报错
关键配置项与易踩的坑
默认配置(DOMPurify.sanitize(html))能拦住 95% 的常见 XSS,但业务需要更细粒度控制时,必须显式传参。
- 允许链接但强制加安全属性:
ADD_ATTR: ['target']+ 在afterSanitizeAttributeshook 中统一设rel="noopener noreferrer" - 禁用危险标签但保留 SVG(电商商品描述常用):
FORBID_TAGS: ['script', 'iframe'],同时启用ALLOWED_TAGS白名单并包含'svg'和'path' - 不要盲目开启
USE_PROFILES: {html: true}:它会激进移除所有style属性,导致加粗、颜色等基础格式丢失 - 避免在 hook 中操作真实 DOM 节点:hook 是在内存 DOM 树中遍历,
node.parentNode可能为null,不要尝试appendChild或修改真实页面结构
Vue/React 中渲染时的正确姿势
前端框架的响应式机制不改变 DOMPurify 的净化逻辑,但渲染方式决定风险是否落地。
- Vue 中禁止直接
v-html="rawContent";应改为v-html="sanitizeHTML(rawContent)",其中sanitizeHTML是封装了DOMPurify.sanitize()的函数 - React 中不要用
dangerouslySetInnerHTML={{__html: rawContent}};先净化再赋值:{__html: DOMPurify.sanitize(rawContent)} - 若用 TypeScript,注意
DOMPurify.sanitize()返回类型是string | TrustedHTML,需配合Trusted Types策略或显式断言类型,否则编译报错
最容易被忽略的一点:DOMPurify 不处理 URL 重定向或 CSP 绕过类攻击。它只管 HTML 结构安全。如果你允许用户填写跳转链接,仍需在后端校验协议白名单(仅 http://、https://、/),不能全交给前端净化。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











