React中使用dangerouslySetInnerHTML时如何有效防止XSS攻击?

司马怡博 阅读 24

我在做一个可以渲染富文本内容的功能,直接用dangerouslySetInnerHTML渲染用户提交的HTML字符串时,发现能被注入恶意脚本。虽然用了htmlspecialchars转义,但页面样式完全乱了:


.user-content {
  font-size: 1.2em;
  .danger {
    color: red;
  }
}

尝试过用DOMPurifysanitize,但不确定是否需要结合其他措施。直接转义导致CSS类名也被转义失效了,有没有更稳妥的防护方法?

我来解答 赞 5 收藏
二维码
手机扫码查看
2 条解答
Newb.瑞静
dangerouslySetInnerHTML 渲染富文本确实是个常见的需求,但安全问题也确实让人头疼。我之前也碰到过类似的情况,最后是用 DOMPurify 解决的。

DOMPurify 是一个专门用来清理 HTML 的库,可以有效防止 XSS 攻击。它会移除所有不安全的标签和属性,同时保留合法的 HTML 和样式。你可以这样用:

import DOMPurify from 'dompurify';

function sanitizeHtml(html) {
return { __html: DOMPurify.sanitize(html) };
}

function UserContent({ content }) {
return <div dangerouslySetInnerHTML={sanitizeHtml(content)} />;
}


这里的关键点是,DOMPurify.sanitize 会帮你过滤掉像 <script> 这样的危险标签,同时保留像 <p><span> 和 CSS 类名这些无害的内容。你提到样式乱了的问题,可能是因为转义的时候把 CSS 类名也转义了,而 DOMPurify 不会有这个问题。

如果你需要支持更复杂的场景,比如允许某些特定的标签或属性,可以通过配置 DOMPurify 来实现。比如这样:

const cleanHtml = DOMPurify.sanitize(dirtyHtml, {
ALLOWED_TAGS: ['p', 'span', 'strong', 'a'],
ALLOWED_ATTR: ['href', 'class']
});


另外,记得在服务端也做一层防护,别光靠前端处理。虽然前端用 DOMPurify 已经很稳妥了,但多一道防线总是好的。我们团队之前就是因为只依赖前端过滤,结果被绕过了,差点出大事,真是教训深刻啊。

总结一下,推荐用 DOMPurify 来清理用户提交的 HTML,既能防止 XSS 攻击,又能保留合法的样式和结构。如果还有其他特殊需求,可以根据实际情况调整配置。
点赞
2026-02-19 18:26
夏侯金壵
直接用 dangerouslySetInnerHTML 渲染用户输入的 HTML 是高危操作,htmlspecialchars 是服务端转义用的,用来处理前端富文本会把标签都变成字符实体,样式当然失效。你看到的问题就是因为整个 HTML 被当成纯文本输出了。

推荐的做法是使用 DOMPurify 进行内容净化,它能自动过滤 script、onerror 等恶意标签和事件属性,同时保留合法的标签和 class 属性。你之前尝试用 DOMPurify 的方向完全正确,不需要再加 htmlspecialchars。

安装:

npm install dompurify


在 React 中使用:

import DOMPurify from 'dompurify';

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


DOMPurify 默认配置已经很安全,支持白名单机制,比如你可以限制只允许 p、div、span、strong 和特定 class:

const clean = DOMPurify.sanitize(html, {
ALLOWED_TAGS: ['p', 'div', 'span', 'strong'],
ADD_ATTR: ['class']
});


注意:如果后端存储的是原始未转义的 HTML,确保在存储时也做过基本校验,防止“存储型 XSS”。前后端都要有防护,但前端展示一律用 DOMPurify 处理。

总结:别用 htmlspecialchars 处理要渲染成 HTML 的内容,用 DOMPurify 净化后再通过 dangerouslySetInnerHTML 输出,这是目前社区公认最稳妥的方案。
点赞 2
2026-02-11 11:04