flawopen.com/XSS in JavaScript/DOMPurify and innerHTML
DOMPurify 足以让 innerHTML 安全吗?
如果 DOMPurify 的输出未经后续修改就直接进入 HTML 注入点,它是可靠的富 HTML 允许列表清理器。可以把它想成货物在入库口接受检查:如果之后被重新包装或从别的入口送入,最初检查就无法覆盖最终内容。普通文本请用 textContent,避免解析 HTML。
// 使用旧版本/策略在保存时清理。 saveToDb(DOMPurify.sanitize(input)); // 后续代码未经复核就信任存储字符串。 el.innerHTML = fetchedFromDb;
// 需要富 HTML 时,使用当前清理库 // 并在写入 HTML 上下文前立即处理。 el.innerHTML = DOMPurify.sanitize(untrustedHtml, { USE_PROFILES: { html: true }, }); // 普通文本不要作为 HTML 解析。 textNode.textContent = untrustedText;
为什么只在保存时清理不够稳妥
保存时清理本身不一定不安全,但会形成陈旧数据边界:清理器修复漏洞、策略改变或某条路径跳过清理后,渲染器仍可能信任旧输出。应在渲染时用当前版本和目标上下文的策略再次清理。插入前不要修改清理后的标记,也不要交给其他库处理;后处理可能使清理失效。
配置和输出上下文很重要
DOMPurify 默认允许 HTML、SVG 和 MathML。如果只需要 HTML,请用 USE_PROFILES: { html: true } 缩小配置。未经审查不要扩大标签或属性范围。DOMPurify 不清理 CSS,也不阻止所有外部资源请求;输出只能用于 HTML 上下文,不要复用到 JavaScript、属性、XML、SVG 或 CSS。
Trusted Types 与服务端渲染
浏览器支持时,通过 Content Security Policy 强制使用 Trusted Types,拒绝未经批准策略处理的字符串写入 HTML 注入点。DOMPurify 可以返回 TrustedHTML,这能减少误用 sink,但无法修复不安全配置或后处理。服务端使用时,DOMPurify 依赖 DOM 实现:保持 jsdom 更新,安全敏感的清理不要与 happy-dom 搭配。
生产环境检查清单
- ✓普通文本使用 textContent。只有产品确实需要展示受限富 HTML 时才使用 DOMPurify。
- ✓在最终 HTML 注入点使用当前 DOMPurify 版本和经审查的最小允许列表清理;之后不要修改结果。
- ✓将输出保持在 HTML 上下文中。不要复用于 JavaScript、CSS、属性、XML、SVG 或其他解析上下文。
- ✓一并审查持久化的 setConfig()、hooks、ADD_TAGS/ADD_ATTR、服务端 DOM 版本及 Trusted Types 策略/CSP。
搜索 HTML 注入点
rg -n -g '*.{js,ts,jsx,tsx}' '(innerHTML|outerHTML|insertAdjacentHTML|document\.write|dangerouslySetInnerHTML)' .