Trusted Types 必须由服务器通过 HTTP 响应头启用,配合 JS 策略注册与 DOM 操作改造才生效;meta 标签无效,策略须在 DOM 加载前注册,仅拦截 script 执行类 sink(如 innerHTML、insertAdjacentHTML),createHTML 需真正净化而非透传。

HTML 本身不能创建 Trusted Types——它必须由服务器通过 HTTP 响应头激活,再配合 JS 策略定义和 DOM 操作改造才能生效。单独在 HTML 文件里加 <meta>、<script> 或任何属性,都不起作用。
为什么 <meta http-equiv="Content-Security-Policy"> 无效
浏览器明确不支持用 <meta> 标签启用 require-trusted-types-for 或 trusted-types 指令。即使你写了:
<meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script'; trusted-types default">
所有 innerHTML 赋值仍会静默通过,不拦截、不报错、不警告。
- 仅旧版 Firefox(已淘汰)曾部分支持
<meta>CSP,但完全不支持 Trusted Types 相关指令 - 现代 Chrome(83+)、Edge(83+)、Safari(16.4+)全部忽略该写法
- 服务端必须返回真实 HTTP 响应头,例如 Nginx 配置:
add_header Content-Security-Policy "require-trusted-types-for 'script'; trusted-types default";
JS 策略必须在 DOM 加载前注册
trustedTypes.createPolicy() 调用必须发生在任何 innerHTML 等 sink 被调用之前;否则策略未就绪,赋值直接失败或抛 TypeError: trustedTypes is undefined。
立即学习“前端免费学习笔记(深入)”;
- 把策略脚本放在
<head>最顶部的<script>中,且不能加async、defer或type="module" - 不要在
DOMContentLoaded或window.onload里注册——太晚了 - 检查是否生效:刷新页面后打开 DevTools → Console,看是否有
Failed to set the 'innerHTML' property或Trusted Types policy creation failed
哪些 DOM 操作必须改,哪些不用动
Trusted Types 只拦截可能执行脚本的 sink,不是所有字符串赋值都管。重点盯住三类:
- ✅ 必须改:
element.innerHTML = raw→ 改为element.innerHTML = policy.createHTML(raw) - ✅ 同样被拦但常被漏:
element.insertAdjacentHTML()、document.write()、location.assign(url)、iframe.srcdoc = html - ❌ 不用改:
element.textContent、element.setAttribute('data-id', val)、JSON.parse()、location.href = 'https://example.com'(非 javascript: 协议)
注意:location.href = 'javascript:alert(1)' 会被拦,但 location.href = 'https://...' 不会——后者不触发脚本执行。
createHTML 函数不能只是透传或简单转义
策略里的 createHTML 是封装器,不是过滤器。返回值必须是经过实际净化的内容,否则等于没开防护。
- ❌ 错误:
createHTML: input => input(裸字符串直返,绕过一切) - ❌ 危险:
createHTML: input => input.replace(/&/g, '&')(纯文本转义防不住<img onerror=...>) - ✅ 推荐:
createHTML: input => DOMPurify.sanitize(input, { RETURN_TRUSTED_TYPE: true })(需 DOMPurify ≥ 3.0) - ⚠️ 注意:
policy.createHTML()返回的是字符串,浏览器内部自动包装为TrustedHTML;不要手动new TrustedHTML(),浏览器不暴露构造函数
真正难的不是写策略,而是识别所有 sink 调用点——比如 DOMParser.parseFromString(html, 'text/html') 和 el.outerHTML = html 同样被拦截,但团队常只改 innerHTML 就上线,结果功能异常却查不出原因。


















