FlawOpen

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 是纵深防御,不能替代清理。

上线前检查

常见问题

禁用原始 HTML 就能让 Markdown 安全吗?

它移除了一个输入功能,但不能单独证明安全。还要检查链接、图片、扩展、生成的 HTML 和插入上下文;写入 HTML 插入点前应清理输出。

能否在清理后再修改 HTML?

应避免这样做。后续改动可能引入不安全标记或使清理器的判断失效。先完成转换,再最后执行清理。

DOMPurify 能让所有上下文中的输出都安全吗?

不能。应按其威胁模型用于 HTML 片段,及时更新并采用严格策略;不要把结果复用到 JavaScript 或 CSS 字符串等其他上下文。

参考资料

另请参阅 XSS 跨站脚本攻击(CWE-79):原理与各编程语言的防护方法 — flawopen.com Svelte 默认能防止 XSS 吗? 上传 SVG 有 XSS 风险吗? Vue v-html 的 XSS 风险 WKWebView loadHTMLString 能安全显示不可信内容吗? 反射型、存储型与 DOM 型 XSS 有何区别? Android addJavascriptInterface 的安全风险