富文本编辑器场景下的 XSS 过滤与白名单设计

在 Web 应用开发中,富文本编辑器几乎是内容型产品的标配。无论是博客后台、论坛发帖、商品详情编辑,还是企业级 CMS 系统,用户都希望能够像使用 Word 一样对内容进行加粗、变色、插入链接、上传图片等操作。然而,富文本编辑器在带来便利的同时,也打开了一扇通往 XSS(跨站脚本攻击)的大门。

web 安全 的众多议题中,xss 长期占据 OWASP Top 10 的重要位置,而富文本编辑器场景下的 XSS 过滤,则是其中最具挑战性的问题之一。本文将从实际场景出发,讨论如何设计一套合理的白名单过滤机制,并顺带梳理 sql 注入csrf 等常见风险与 安全加固 的整体思路。

一、为什么富文本编辑器是 XSS 的重灾区

普通输入框的 XSS 防御相对简单:对用户输入进行 HTML 实体编码,让 < 变成 &lt;> 变成 &gt;,浏览器就不会把它当作标签解析。但富文本编辑器恰恰相反——它需要保留一部分 HTML 标签和属性,才能呈现出用户想要的格式。

这就产生了一个核心矛盾:

  • 如果全部转义,富文本就失去了意义;
  • 如果全部放行,攻击者就可以插入 <script><img onerror=...> 等恶意代码。

更麻烦的是,富文本内容往往会被存储到数据库,然后在其他用户的浏览器中渲染出来。这意味着一次注入,可能影响所有查看该内容的用户,形成典型的存储型 XSS

常见的攻击向量包括:

  • <script>alert(document.cookie)</script>
  • <img src=x onerror=alert(1)>
  • <a href="javascript:alert(1)">点击</a>
  • <svg/onload=alert(1)>
  • 利用 CSS 表达式或 style 属性进行注入

二、黑名单为什么不可靠

很多开发者第一反应是“把危险标签和关键字过滤掉”,也就是黑名单方案。例如屏蔽 <script>onerrorjavascript: 等。但黑名单在富文本场景下几乎注定失败,原因有三:

  1. HTML 语法过于灵活:大小写混写、属性换行、实体编码、注释穿插,都能绕过简单的字符串匹配。例如 <scr<script>ipt> 在部分过滤逻辑下会被还原成 <script>
  2. 浏览器解析存在容错:浏览器对畸形 HTML 有很强的纠错能力,攻击者可以利用这一点构造出过滤器看不懂、浏览器却会执行的代码。
  3. 新向量层出不穷:今天屏蔽了 onerror,明天可能又出现新的 SVG 事件或 CSS 注入方式。

因此,安全社区普遍推荐的做法是:白名单机制

三、白名单设计的核心原则

白名单的核心思想是:只允许明确安全的标签、属性和协议通过,其余一律丢弃或转义。设计时建议遵循以下原则。

1. 标签白名单

只保留富文本必需的标签,例如:

  • 文本结构:pbrstrongemusblockquote
  • 标题:h1 ~ h6
  • 列表:ulolli
  • 链接与图片:aimg
  • 表格:tabletheadtbodytrthtd
  • 代码:precode

scriptiframeobjectembedforminput 等标签应坚决排除。

2. 属性白名单

不同标签允许的属性应分别定义。例如:

  • a:只允许 hreftitletarget
  • img:只允许 srcalttitlewidthheight
  • 全局属性:可考虑 class,但要谨慎,因为 class 可能配合前端框架造成意外行为

特别注意,所有 on* 事件属性(onclickonerroronload 等)必须全部禁止。

3. 协议白名单

hrefsrc 等 URL 属性,必须校验协议。只允许:

  • http:
  • https:
  • mailto:
  • 相对路径(如 /images/a.png

坚决禁止 javascript:data:(除非明确需要且经过严格处理)、vbscript: 等。

4. 样式处理

style 属性是另一个高风险点。如果业务不需要自定义样式,建议直接禁止。若必须保留,应只允许有限的 CSS 属性(如 colorfont-sizetext-align),并过滤 expressionurl()behavior 等危险值。

四、实现建议与工具选择

在实际工程中,不建议自己从零编写正则过滤器。推荐使用成熟的安全库:

  • 前端:DOMPurify 是目前最广泛使用的方案,支持自定义白名单,能有效处理各种浏览器解析差异。
  • 后端:Java 可使用 OWASP Java HTML Sanitizer,PHP 可使用 HTMLPurifier,Python 可使用 bleach。

典型流程是:前端用 DOMPurify 做即时预览过滤,后端在入库前再做一次严格过滤。永远不要只信任前端,因为攻击者可以直接构造请求绕过浏览器。

此外,还要注意:

  • 过滤应在服务端作为最后一道防线;
  • 富文本内容在输出到页面时,根据上下文选择正确的编码方式;
  • 配合 CSP(内容安全策略),限制内联脚本执行,进一步降低 XSS 影响。

五、与 SQL 注入、CSRF 的关系

虽然本文聚焦 XSS,但在 web 安全 体系中,各类风险往往相互关联。sql 注入 通过拼接恶意 SQL 语句窃取或篡改数据,防御的核心是参数化查询;csrf 则利用用户已登录状态伪造请求,防御手段包括 CSRF Token、SameSite Cookie 等。

一个完整的 安全加固 方案,通常包括:

  • 输入校验与输出编码
  • 富文本白名单过滤
  • 参数化查询防 SQL 注入
  • CSRF Token 与 SameSite 策略
  • 最小权限原则与安全响应头
  • 定期安全测试与代码审计

六、总结

富文本编辑器场景下的 XSS 过滤,本质上是在“功能”与“安全”之间寻找平衡。黑名单看似简单,实则漏洞百出;白名单虽然实现成本更高,但能从根本上限制攻击面。设计时应明确标签、属性、协议三层白名单,借助成熟库完成过滤,并在服务端保留最终校验。

安全从来不是单一措施能够解决的,只有把 XSS 过滤、SQL 注入防护、CSRF 防御以及整体安全加固结合起来,才能构建真正可靠的内容型 Web 应用。

未经允许不得转载:任鹏个人博客 » 富文本编辑器场景下的 XSS 过滤与白名单设计

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏