flawopen.com/JavaScript 中的 XSS/dangerouslySetInnerHTML
React 的 dangerouslySetInnerHTML 安全吗?
参考页面
简短回答
把普通 JSX 想成标签打印机:文本仍是文本。dangerouslySetInnerHTML 则像一台会把字符串解析成 HTML 的印刷机。如果字符串包含攻击者可控的内容,浏览器可能将其视为可执行的标记。只有在 HTML 已明确可信,或已针对准确的 HTML 上下文完成清理时,才使用这个输出点。
为什么普通 JSX 不需要它
有风险 — 未处理的 HTML
function Comment({ html }) {
return <p dangerouslySetInnerHTML=
{{ __html: html }} />;
}
安全 — 普通 JSX 插值
function Comment({ text }) {
return <p>{text}</p>;
}
何时适合使用 dangerouslySetInnerHTML?
仅当产品必须保留无法用普通 React 子节点表示的受限富文本格式时才使用。CMS、编辑器或 Markdown 渲染器并不会自动可信:存储内容和渲染器输出仍可能包含不可信标记。定义允许的元素和属性,使用持续维护的 HTML 清理库(如 DOMPurify)清理,并将结果直接传入该输出点。
正确使用方式
在渲染边界清理
在赋值给 dangerouslySetInnerHTML 之前立即使用 DOMPurify 等持续维护的库清理内容。不要用正则表达式清理 HTML。清理后避免再修改字符串;后续转换可能破坏清理器的安全保证。及时更新清理库及其解析环境。
限制允许的标记
仅禁止已知标签的黑名单并不完整:风险也可能来自属性、URL 字段、命名空间和解析器行为。根据功能需要列出少量允许的元素和属性,并按该策略配置清理器。还应根据产品允许的目标单独检查链接和其他包含 URL 的属性。
如何检查代码
grep -rn "dangerouslySetInnerHTML" --include="*.jsx" --include="*.tsx" .对每个匹配项,追踪值的来源和所有转换。将用户输入、导入内容和存储的富文本视为不可信;确认清理策略适用于输出上下文,并且之后没有步骤修改清理结果。
常见问题
Markdown 渲染会自动保证安全么?
这取决于渲染器及其配置。检查是否接受原始 HTML、是否清理输出;仅转换 Markdown 并不会自动使 HTML 安全。
这也适用于 Vue 的 v-html 吗?
适用。v-html 同样会绕过框架通常的文本插值,将 HTML 交给浏览器。应将其视为 HTML 输出点,并按适当策略清理不可信内容。