React
HTML 转义
React 默认对所有文本内容进行 HTML 转义,以防止 XSS 攻击。若要渲染真正的 HTML,可以使用 dangerouslySetInnerHTML 属性,但这需要谨慎处理。
一、基本用法
dangerouslySetInnerHTML 接收一个对象,其中 __html 键包含要渲染的 HTML 字符串。
function HTMLRenderer({ html }: { html: string }) {
return <div dangerouslySetInnerHTML={{ __html: html }} />
}
function Demo(params: type) {
return <HTMLRenderer html="<p>这是<strong>HTML</strong>内容</p>" />
}
// 使用示例这是 React 对浏览器 innerHTML 的替代方案。
二、为什么叫 "dangerous"
属性名中的 "dangerous" 是有意的警告——使用 dangerouslySetInnerHTML 存在 XSS(跨站脚本攻击)风险。
// ✗ 危险:用户输入可能包含恶意脚本
function UnsafeComponent({ userContent }: { userContent: string }) {
return <div dangerouslySetInnerHTML={{ __html: userContent }} />
}
// 假设 userContent = '<img src=x onerror="alert(\'hacked\')">'
// 脚本会被执行安全原则:只在 完全信任 内容来源时才使用。
三、安全的使用场景
✓ 来自可信 CMS 系统
function CMSContent({ htmlFromCMS }: { htmlFromCMS: string }) {
return <div dangerouslySetInnerHTML={{ __html: htmlFromCMS }} />
}✓ 经过处理的 Markdown 转 HTML
import { marked } from 'marked'
import DOMPurify from 'dompurify'
function MarkdownPreview({ markdown }: { markdown: string }) {
const html = marked(markdown)
const sanitized = DOMPurify.sanitize(html)
return <div dangerouslySetInnerHTML={{ __html: sanitized }} />
}✓ 富文本编辑器输出(经过清理)
function RichTextDisplay({ editorOutput }: { editorOutput: string }) {
const sanitized = DOMPurify.sanitize(editorOutput)
return <div dangerouslySetInnerHTML={{ __html: sanitized }} />
}四、最佳实践
1. 使用内容清理库
永远用 DOMPurify 或类似库清理不完全可信的 HTML:
import DOMPurify from 'dompurify'
function SafeHTML({ html }: { html: string }) {
const clean = DOMPurify.sanitize(html)
return <div dangerouslySetInnerHTML={{ __html: clean }} />
}2. 清晰标识内容来源
在代码中明确注释为什么这里使用 dangerouslySetInnerHTML:
function TrustedContent({ html }: { html: string }) {
// HTML 来自后端 CMS,已被系统管理员控制
return <div dangerouslySetInnerHTML={{ __html: html }} />
}五、替代方案
如果只需要展示普通文本,不要使用 dangerouslySetInnerHTML
// ✓ React 会自动转义 HTML 字符,防止 XSS
function SafeText({ text }: { text: string }) {
return <div>{text}</div>
}
// 示例:即使 text = "<script>alert('x')</script>"
// 也会被安全地显示为文本,不会执行脚本使用 JSX 而不是 HTML 字符串
// 当你可以控制结构时,直接用 JSX 更安全更清晰
function SafeComponent({ title }: { title: string }) {
return (
<div>
<h1>{title}</h1>
<p>这是一个段落</p>
</div>
)
}核心原则:React 默认转义所有内容是为了保护你。只在有明确的必要且完全信任源时才用
dangerouslySetInnerHTML,并且总是搭配内容清理库使用。