必须配CSP响应头,否则Trusted Types形同虚设;关键头为Content-Security-Policy: require-trusted-types-for 'script'; trusted-types default,且default策略名不可省略,<meta>标签无效。

必须配 CSP 响应头,否则 Trusted Types 形同虚设
浏览器只在收到正确的 Content-Security-Policy 响应头后才开启运行时拦截。仅在 JS 里调用 trustedTypes.createPolicy() 不会产生任何防护效果。
关键头必须是 HTTP 响应头(<meta> 无效),且包含两个指令:
-
require-trusted-types-for 'script':强制所有可能执行脚本的 DOM sink(如innerHTML、insertAdjacentHTML、document.write)只接受 Trusted 类型 -
trusted-types default;:声明允许使用的策略名;default是必需的占位名,不能省略;若用自定义名(如htmlPolicy),必须写成trusted-types htmlPolicy;
开发阶段可用 Content-Security-Policy-Report-Only 先收集违规,避免上线即崩。
哪些 DOM 操作会被拦截,哪些不会
拦截只发生在明确写入、且目标属性被规范列为“需要 Trusted 类型”的时刻。不是所有字符串赋值都管。
立即学习“前端免费学习笔记(深入)”;
会被拦截的典型操作:
-
element.innerHTML = '<script>...</script>'→ 抛TypeError: Assignment to innerHTML attribute was blocked -
element.outerHTML、element.insertAdjacentHTML()、document.write()、location.assign('javascript:...')
不会被拦截的操作(它们本身不触发脚本执行):
-
element.textContent、element.setAttribute('data-id', ...)、JSON.parse() -
element.insertAdjacentText()、location.href = 'https://...'(但location.assign(string)会拦)
策略必须做真实净化,不能只是透传
createHTML 函数不能直接返回输入参数——那等于没过滤。必须实际处理内容,比如用 DOMPurify.sanitize(input, { RETURN_TRUSTED_TYPE: true })。
常见错误写法:
-
createHTML: (input) => input→ 绕过净化,等同于裸字符串赋值 -
createHTML: (input) => `<div>${input}</div>`→ 手动拼接后再进策略,仍可能带恶意标签 - 策略名声明为
htmlPolicy,但 CSP 头里只写了trusted-types default;→ 浏览器拒绝使用该策略
正确姿势:策略职责单一,富文本、用户昵称、评论内容应分不同策略;每个策略名显式列在 CSP 的 trusted-types 列表中。
框架和第三方库可能绕过 Trusted Types
React 的 dangerouslySetInnerHTML、Vue 的 v-html、Angular 的 [innerHTML] 是否被拦,取决于框架是否主动适配 Trusted Types API。目前主流版本尚未默认集成,需手动桥接或依赖插件。
更隐蔽的风险点:
- 第三方 UI 库内部调用
innerHTML(如某些弹窗、Tooltip 组件) - 未声明策略名却调用
trustedTypes.getPolicyByName('xxx')→ 返回undefined,后续调用直接报错 - 仍存在
eval('...')、setTimeout(string)、setInterval(string)等传统 XSS 向量,Trusted Types 不覆盖这些
真正起作用的从来不是策略函数本身,而是那个服务端发出的、带 require-trusted-types-for 的响应头——漏掉它,整个机制就断在第一环。



















