trusted types 不能彻底防御 dom xss,仅当启用 require-trusted-types-for 'script' csp 头、所有 sink 均使用策略生成的 trustedhtml、且无间接调用遗漏时才生效;js 创建策略本身无防护作用,必须配合 csp 强制模式。

Trusted Types 不能“彻底防御” DOM XSS,它只在满足三个硬性条件时才生效:HTTP 响应头启用 require-trusted-types-for 'script'、所有 sink 操作都走策略构造的 TrustedHTML(或对应类型)、且没有漏掉任何间接调用路径。缺一不可。
必须通过 CSP 响应头开启强制模式,JS 创建策略本身不拦截任何操作
浏览器只在收到 Content-Security-Policy: require-trusted-types-for 'script' 后,才会对 innerHTML、insertAdjacentHTML、document.write 等 sink 抛出 TypeError: Failed to set an illegal value。仅靠 JS 调用 window.trustedTypes.createPolicy 不会产生任何防护效果——它只是定义了一个工厂函数,没头没尾。
- 开发阶段可用
Content-Security-Policy-Report-Only: require-trusted-types-for 'script'; report-uri /csp-report先捕获违规,避免上线炸锅 -
trusted-types指令需同步声明允许的策略名,例如trusted-types default securePolicy;若写成trusted-types 'none',连default策略都会被禁用 - 策略名
default是特殊关键字:当代码里调用policy.createHTML(input)但未显式指定策略名时,浏览器会 fallback 到default策略;不设它,TrustedHTML构造直接失败
不要在策略里做 HTML 解析或白名单过滤
策略函数本质是同步纯函数,执行在主线程,且每次 DOM 写入都会触发。若在里面调用 DOMPurify.sanitize 或正则匹配标签,性能会断崖下跌,还可能因解析逻辑缺陷被绕过。
- 优先用
textContent替代innerHTML——90% 的场景根本不需要富文本渲染 - 必须插 HTML 时,用预编译模板(如 Lit 的
htmltag)或服务端渲染,而非客户端拼接字符串 - 若真要动态生成,策略里只做最小必要处理:比如
input.replace(/, ',但注意这仍不是万全之策,仅比裸字符串稍强
常见 sink 漏洞点远不止 innerHTML
innerHTML 只是冰山一角。以下操作同样受控,但容易被忽略:
-
el.outerHTML = htmlString→ 需用policy.createHTML()构造 -
el.insertAdjacentHTML('beforeend', htmlString)→ 同样拦截,必须传TrustedHTML -
location.href = 'javascript:alert(1)'→ 属于'script'类别,会被拦;但location.assign(new TrustedURL(...))放行 -
eval('alert(1)')和setTimeout('alert(1)', 100)→ 字符串形式均被拒绝 -
document.write、DOMParser.parseFromString(html, 'text/html')→ 同样需要TrustedHTML
框架内部调用(如 React 的 dangerouslySetInnerHTML、Vue 的 v-html)是否受控,取决于其底层是否调用原生 sink。React 并不自动适配 Trusted Types,需手动 wrap。
框架集成与逃逸风险:shadowRoot、setAttribute、第三方库
不是所有 DOM 操作都被拦截。这些是已知逃逸路径:
-
el.setAttribute('innerHTML', value)—— 无效属性,不触发 sink,完全绕过 -
shadowRoot.innerHTML = htmlString—— Chrome 已支持拦截,但 Safari 17.4+ 才稳定,旧版失效 - Web Components 中通过
slot注入、或使用innerHTML在非标准上下文(如 SVGforeignObject)中 —— 浏览器尚未统一覆盖 - 某些 UI 库(如旧版 Quill、TinyMCE)内部直接操作
document.execCommand或RangeAPI —— 不经过 Trusted Types 校验链
真正难防的不是 innerHTML = x 这种明面上的写法,而是那些隐式触发 DOM 修改的链路:比如一个富文本编辑器把用户输入转成 AST 后再序列化为 HTML,中间任何一步没走策略,整条链就崩了。










