setter 本身不能直接实现秒级拦截或清洗富文本脏数据,但可作为赋值阶段的数据校验与转换入口,在业务逻辑前完成白名单标签过滤、危险标签剔除、style 保守处理,并配合 dompurify 或 proxy 实现同步净化与日志记录,同时需区分展示与编辑器内部 html,且必须服务端二次校验兜底。

Setter 属性本身不能直接实现“秒级拦截”或“清洗富文本脏数据”,但它可以作为数据校验与转换的轻量入口,在赋值阶段及时干预,配合合理的策略,达到接近实时的净化效果。关键不在于 Setter 多快,而在于它能否在数据进入业务逻辑前,就完成结构判断、标签过滤和基础 XSS 防御。
用 Setter 封装 HTML 净化逻辑
将富文本内容的赋值操作收口到一个响应式属性上,利用 Setter 对原始 HTML 做最小必要清洗:
- 只允许白名单标签(如 p、br、strong、em、ul、ol、li)
- 自动剔除 script、iframe、onerror/onload 等危险标签和内联事件
- 对 style 属性做保守处理(如仅保留 color、font-size 等安全样式,或直接移除)
- 使用 DOMPurify 或自研轻量解析器(避免正则删 script——不可靠)
结合 Proxy 实现更灵活的拦截时机
单纯靠 Object.defineProperty 的 Setter 在 Vue2 或纯 JS 类中适用,但若需监听深层嵌套、数组变更或批量赋值,建议用 Proxy 包裹编辑器数据对象:
- 拦截 set 操作时,对 target[key] 的新值做同步净化,返回净化后结果
- 可附加日志:记录被拦截的非法标签、触发来源(如粘贴 vs API 注入)
- 配合防抖(如 300ms 内连续赋值只触发一次清洗),避免高频输入卡顿
与编辑器生命周期对齐,避免清洗过度
清洗不是越狠越好——过度剥离会破坏编辑器的内部结构(如 Quill 的 ql- 类名、Draft.js 的自定义 block):
- 区分“展示用 HTML”和“编辑器内部 HTML”:Setter 只处理最终要渲染到页面的内容,不碰编辑器 state
- 若编辑器提供 onTextChange / onChange 钩子,优先在那里调用清洗,而非依赖外部 Setter
- 对粘贴内容单独增强:监听 paste 事件,用 document.execCommand('insertHTML') 前先净化,比依赖 Setter 更前置
补充服务端兜底,不信任任何前端清洗
前端 Setter 清洗只是用户体验优化层,绝不能替代服务端校验:
- 所有提交到后端的富文本,必须用服务端库(如 Java 的 Jsoup、Python 的 Bleach、Node 的 sanitize-html)二次净化
- 前端可传一个 checksum 或简单哈希,服务端比对清洗前后差异,发现绕过行为可告警
- 对含图片/附件的富文本,额外校验 src 是否为可信域名、是否经过上传接口中转
不复杂但容易忽略:Setter 是守门人,不是清洁工。它的价值在于让脏数据止步于赋值那一刻,而不是替你解决所有 HTML 安全问题。










