React 组件 innerHTML 安全陷阱:从“XSS 漏洞”到“安全渲染”的求生指南

正文目录

  1. 为什么 innerHTML 是 XSS 温床?
  2. 3 大高危场景 & 现场复原
  3. 安全方案:sanitize + 替代 API
  4. 性能对比 & DevTools 实测
  5. 一键 Checklist(零 XSS)

一、为什么 innerHTML 是 XSS 温床?

React 默认自动转义

<div>{userInput}</div>  // &lt;script&gt; 被转义

但一旦使用 dangerouslySetInnerHTML,转义被完全绕过

<div dangerouslySetInnerHTML={{__html: userInput}} />

输入中的 <script><img onerror><svg onload> 会直接执行!


二、3 大高危场景 & 现场复原

① 用户富文本未净化

// ❌ 直接注入
<div dangerouslySetInnerHTML={{__html: comment}} />

输入:

<img src=x onerror="alert(document.cookie)" />

修复:用 DOMPurify 净化

npm i dompurify
import DOMPurify from 'dompurify';

<div dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(comment)}} />

② 链接 href 未净化

// ❌ 直接拼接
<a href={`data:text/html,<script>alert(1)</script>`}>Click</a>

修复:只允许 http/https

const isSafeUrl = (url) => /^https?:\/\//.test(url);
<a href={isSafeUrl(url) ? url : '#'} target="_blank" rel="noopener">Click</a>

③ 样式内联未净化

// ❌ 直接内联
<div style={{ backgroundImage: `url(${userPic})` }} />

输入:

javascript:alert(1)

修复:校验协议 + base64

const isSafeImage = (url) => /^https?:\/\/|data:image/.test(url);
<div style={{ backgroundImage: isSafeImage(url) ? `url(${url})` : 'none' }} />

三、安全方案:sanitize + 替代 API

① DOMPurify 净化(推荐)

npm i dompurify @types/dompurify
import DOMPurify from 'dompurify';

function SafeHtml({ html }) {
  return <div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(html) }} />;
}

② 替代 API:markdown-it + sanitize

npm i markdown-it markdown-it-sanitizer
import md from 'markdown-it';
import sanitizer from 'markdown-it-sanitizer';

const mdRenderer = md().use(sanitizer);
function Markdown({ source }) {
  const html = mdRenderer.render(source);
  return <div dangerouslySetInnerHTML={{ __html: html }} />;
}

③ 纯 React 方案:markdown-to-jsx(零 innerHTML)

npm i markdown-to-jsx
import Markdown from 'markdown-to-jsx';

function SafeMarkdown({ source }) {
  return <Markdown>{source}</Markdown>;   // ✅ 无 innerHTML
}

四、性能对比(DevTools 实测)

方案 XSS 风险 渲染性能 内存占用
raw innerHTML 高危 最快
DOMPurify
markdown-to-jsx

DOMPurify:零 XSS,性能损失 < 5%。


五、一键 Checklist(零 XSS)

  • 所有 dangerouslySetInnerHTML **必须 DOMPurify.sanitize()`
  • 链接 href 只允许 http/https
  • 图片 src **只允许 http/https/data:image`
  • 样式内联 校验协议 + base64
  • 控制台「XSS」= 立即净化 + 替代 API

六、一句话总结

「innerHTML 不安全」= 永远用 DOMPurify 或零 innerHTML 替代。
让净化成为习惯,让 XSS 永远进不来!


最后问候亲爱的朋友们,并邀请你们阅读我的全新著作

📚 《 React开发实践:掌握Redux与Hooks应用 》

在这里插入图片描述

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐