返回
创建于
状态公开

React 中如何安全地渲染富文本

在 React 应用中使用富文本,不可避免地要面对各种安全隐患,尤其是 XSS(跨站脚本攻击)。本文将从渲染原理、常见库对比、关键安全策略以及与其他领域的关联等角度出发,帮助你系统掌握如何在 React 环境下安全、可控地渲染富文本。


一、渲染富文本需要警惕的安全问题

  1. XSS 攻击
    当应用允许用户输入任意 HTML 代码并将其直接渲染到页面中时,恶意的 <script> 或事件属性(如 onclick)可能被注入,导致浏览器执行不受控的脚本,进而窃取用户信息或劫持会话。

  2. React 中的默认保护
    React 在大多数情况下会对文本进行转义,这就能避免绝大部分的 XSS 问题。但如果使用 dangerouslySetInnerHTML 来直接插入富文本,那么必须做好必要的安全过滤,否则就可能留下攻击入口。

  3. 前后端的信任边界
    尽管前端可以通过各种库来过滤输入或后端返回的数据,但从安全角度看,后端也应该对接收到的富文本进行严格的筛选与存储。只有形成“前端 + 后端”双重过滤的机制,才能最大程度降低风险。


二、在 React 中使用富文本的常见做法

  1. dangerouslySetInnerHTML

    • 优点:可以将 HTML 字符串直接注入到 DOM 中,适合显示富文本或第三方内容。
    • 缺点:如果内容未经任何安全处理,就存在较大的安全风险。
  2. 第三方富文本编辑器

    • 例如 Draft.js、Quill 等,会对用户输入进行一定程度的处理,并提供转义/过滤的选项。
    • 也需要根据业务需求设置白名单规则,否则依然可能被绕过。

三、常用安全过滤库比较

以下是前端与后端常用的两种 HTML 过滤库,它们都能很好地防范常见的富文本 XSS 注入问题。

1. DOMPurify

  • 定位与适用场景
    主要应用在浏览器端,速度快、易用,社区活跃度高,适合在 React/Vue 等前端项目中直接对富文本进行过滤。
  • 使用示例
    jsx
    1import DOMPurify from 'dompurify';
    2
    3function SafeContent({ htmlString }) {
    4  const safeHtml = DOMPurify.sanitize(htmlString);
    5  return <div dangerouslySetInnerHTML={{ __html: safeHtml }} />;
    6}
  • 特色
    • 通过 ALLOWED_TAGSALLOWED_ATTR 等配置可实现白名单或黑名单。
    • 在浏览器环境中依赖原生 DOM 解析,性能较好。

2. sanitize-html

  • 定位与适用场景
    在前端和后端(Node.js)都能使用,但更多用于服务器端对用户提交内容进行“深度清洗”,再存储到数据库或返回前端。
  • 使用示例
    js
    1import sanitizeHtml from 'sanitize-html';
    2
    3const cleanHtml = sanitizeHtml(dirtyHtml, {
    4  allowedTags: ['b', 'i', 'strong', 'a'],
    5  allowedAttributes: {
    6    a: ['href', 'target']
    7  }
    8});
  • 特色
    • 提供更丰富的配置项与回调钩子,适合需要进行多层规则定制的复杂场景。
    • 默认规则相对严格,可以过滤掉大多数不安全标签和属性。

四、关键安全策略与配置要点

  1. 白名单策略
    最常见也是较为安全的做法是白名单:只允许指定标签和少量可信属性(如链接的 href、图片的 src),禁止所有脚本类标签与内联事件(例如 onclickonload)。

  2. 链接安全
    如果允许 <a> 标签,建议强制添加 rel="noopener noreferrer"target="_blank",以防用户打开新的页面时造成安全或性能隐患。

  3. 前后端双重过滤

    • 后端在存储用户输入之前就进行一次强力过滤,这样数据库里保存的内容默认是安全的。
    • 前端在显示时可以根据需求进行二次过滤,例如使用 DOMPurify 做最终的安全审查。
    • 双管齐下可以大幅降低因配置遗漏或逻辑漏洞带来的风险。
  4. 保留原始内容的必要性
    某些业务场景可能希望保留用户提交的“原始内容”以便后续编辑。此时可以同时存储“原始内容”和“安全过滤后内容”两份,渲染时使用后者,编辑时用前者,做到安全与功能的兼顾。

  5. SSR 与同构应用
    若你的 React 应用采用服务端渲染(SSR),考虑在服务器端也直接调用 DOMPurify(或 sanitize-html)进行过滤,输出给客户端时就已经是安全的 HTML。这样可以避免在前端再次解析与过滤,节省一定的性能开销。


五、与其他重要概念或领域的关联

  1. 网络安全与合规
    安全渲染富文本不仅是技术问题,也事关用户数据安全和合规要求(如 GDPR 等)。在涉及个人信息或敏感数据时,要确保任何可能引入的第三方脚本都受控,并拥有完善的审计机制。

  2. 内容管理系统(CMS)
    许多 CMS 都内置富文本编辑功能,并对用户提交内容进行预处理。如果你使用开源或商用 CMS,需要了解其默认的过滤规则,必要时可自行定制或增加前端过滤。

  3. 黑名单 vs 白名单

    • 黑名单:列出禁止的标签或属性,剩余的全部允许。缺点是存在无法预料的新型攻击向量,很难及时更新黑名单。
    • 白名单:只允许“安全且必要”的标签或属性,对其他全部拒绝。这种方式更安全,但需要根据业务需求定期更新白名单策略。
  4. 性能与扩展性

    • 无论使用哪种过滤库,都需要考虑高并发下的性能损耗。DOMPurify 在前端环境中一般表现良好;sanitize-html 在 Node.js 环境也能保持较优性能。
    • 随着业务规模增长,安全策略和库版本需要定期审计与更新。

六、总结

React 中安全地渲染富文本,最核心的思路就是“用安全过滤库清洗用户提供的 HTML”,然后再通过 dangerouslySetInnerHTML 或类似方式插入 DOM。DOMPurify 与 sanitize-html 均提供了成熟可靠的过滤逻辑,可以帮助我们便捷地对富文本进行白名单或更细粒度的安全控制。

从实际项目出发,前端与后端的双重过滤是最稳妥的做法,既能保证数据库中的数据保持安全,也能在展示给用户之前进行再次校验。结合对链接与事件属性等细节的限制,就能最大程度上避免 XSS 等常见攻击,为用户提供安全的富文本体验。