flawopen.com/XSS/Markdown 渲染
Markdown 渲染能防御 XSS 吗?
参考指南
简短回答
应把 Markdown 生成的 HTML 视为不可信内容。解析器可能保留原始 HTML,因为语法允许这样做;转换 Markdown 并不会清理输出。解析器只是翻译标记的工具,不是安全守卫。
信任边界在哪里
CommonMark 规范规定,形似标签的原始 HTML 会未经转义直接渲染。具体行为取决于解析器、选项、插件和宿主框架。例如,Marked明确警告它不会清理生成的 HTML。Markdown 语法本身不能证明输入安全;清理器必须保护最终的 HTML 插入点。
安全的渲染流程
不安全 — 插入未清理的输出
const html = marked.parse(userMarkdown); container.innerHTML = html; // 解析器输出未经清理
加固 — 在写入 HTML 前立即清理
import DOMPurify from "dompurify";
const html = marked.parse(userMarkdown);
container.innerHTML = DOMPurify.sanitize(html, {
USE_PROFILES: { html: true }
});
示例使用 DOMPurify 的纯 HTML 配置,因为此视图不需要 SVG 或 MathML。只启用产品所需的功能。不要在插入前修改已清理的标记,也不要再交给会改写 HTML 的库处理,否则可能破坏清理保证。如果不需要富文本 HTML,应优先使用框架的安全文本渲染。Content Security Policy 与 Trusted Types 是纵深防御,不能替代清理。
上线前检查
- ✓固定 Markdown 解析器版本,审查原始 HTML、插件和 URL 处理选项。
- ✓在最终 HTML 插入点之前,使用持续维护的白名单清理器清理生成的 HTML。
- ✓将允许的元素、属性和 URL 协议限制在产品需要的范围内。
- ✓清理后不要再编辑或重新解析标记;若必须转换,应在转换后再次清理。
- ✓测试确切的解析器配置和渲染插入点,并保持清理器更新。
常见问题
禁用原始 HTML 就能让 Markdown 安全吗?
它移除了一个输入功能,但不能单独证明安全。还要检查链接、图片、扩展、生成的 HTML 和插入上下文;写入 HTML 插入点前应清理输出。
能否在清理后再修改 HTML?
应避免这样做。后续改动可能引入不安全标记或使清理器的判断失效。先完成转换,再最后执行清理。
DOMPurify 能让所有上下文中的输出都安全吗?
不能。应按其威胁模型用于 HTML 片段,及时更新并采用严格策略;不要把结果复用到 JavaScript 或 CSS 字符串等其他上下文。