测试
- DOMParser-parseFromString-regression.html (在线测试) (源码)
- DOMParser-parseFromString.html (在线测试) (源码)
- DedicatedWorker-block-eval-function-constructor.html (在线测试) (源码)
- DedicatedWorker-constructor-from-DedicatedWorker.html (在线测试) (源码)
- DedicatedWorker-constructor-from-SharedWorker.html (在线测试) (源码)
- DedicatedWorker-constructor.https.html (在线测试) (源码)
- DedicatedWorker-eval.html (在线测试) (源码)
- DedicatedWorker-importScripts.html (在线测试) (源码)
- DedicatedWorker-setTimeout-setInterval.html (在线测试) (源码)
- Document-execCommand.html (在线测试) (源码)
- Document-write-appending-line-feed.html (在线测试) (源码)
- Document-write-exception-order.xhtml (在线测试) (源码)
- Document-write.html (live test) (源码)
- Element-insertAdjacentHTML.html (在线测试) (源码)
- Element-outerHTML.html (live test) (源码)
- Element-setAttribute-respects-Elements-node-documents-globals-CSP-after-adoption-from-TT-realm.html (在线测试) (源码)
- Element-setAttribute-respects-Elements-node-documents-globals-CSP-after-adoption-from-non-TT-realm.html (在线测试) (源码)
- Element-setAttribute.html (在线测试) (源码)
- Element-setAttributeNS.html (在线测试) (源码)
- Element-toggleAttribute.html (在线测试) (源码)
- GlobalEventHandlers-onclick.html (在线测试) (源码)
- HTMLElement-generic.html (live test) (源码)
- HTMLScriptElement-in-xhtml-document.tentative.https.xhtml (在线测试) (源码)
- HTMLScriptElement-internal-slot.html (在线测试) (源码)
- Node-multiple-arguments-tt-enforced.html (在线测试) (源码)
- Node-multiple-arguments.html (在线测试) (源码)
- Range-createContextualFragment.html (在线测试) (源码)
- SVGScriptElement-internal-slot.html (在线测试) (源码)
- ServiceWorker-block-eval-function-constructor.https.html (在线测试) (源码)
- ServiceWorker-eval.https.html (在线测试) (源码)
- ServiceWorker-importScripts.https.html (在线测试) (源码)
- ServiceWorkerContainer-register-from-DedicatedWorker.https.html (在线测试) (源码)
- ServiceWorkerContainer-register-from-ServiceWorker.https.html (在线测试) (源码)
- ServiceWorkerContainer-register-from-SharedWorker.https.html (在线测试) (源码)
- ServiceWorkerContainer-register.https.html (在线测试) (源码)
- SharedWorker-block-eval-function-constructor.html (在线测试) (源码)
- SharedWorker-constructor.https.html (在线测试) (源码)
- SharedWorker-eval.html (live test) (源码)
- SharedWorker-importScripts.html (在线测试) (源码)
- SharedWorker-setTimeout-setInterval.html (在线测试) (源码)
- TrustedType-AttributeNodes.html (在线测试) (源码)
- TrustedTypePolicy-CSP-no-name.html (在线测试) (源码)
- TrustedTypePolicy-CSP-wildcard.html (在线测试) (源码)
- TrustedTypePolicy-createXXX.html (在线测试) (源码)
- TrustedTypePolicyFactory-constants.html (在线测试) (源码)
- TrustedTypePolicyFactory-createPolicy-createXYZTests.html (在线测试) (源码)
- TrustedTypePolicyFactory-createPolicy-cspTests-noNamesGiven.html (在线测试) (源码)
- TrustedTypePolicyFactory-createPolicy-cspTests-none-none-name.html (在线测试) (源码)
- TrustedTypePolicyFactory-createPolicy-cspTests-none-none.html (在线测试) (源码)
- TrustedTypePolicyFactory-createPolicy-cspTests-none-skip.html (在线测试) (源码)
- TrustedTypePolicyFactory-createPolicy-cspTests-none.html (在线测试) (源码)
- TrustedTypePolicyFactory-createPolicy-cspTests-wildcard.html (在线测试) (源码)
- TrustedTypePolicyFactory-createPolicy-cspTests.html (在线测试) (源码)
- TrustedTypePolicyFactory-createPolicy-non-tt-policy-name.html (在线测试) (源码)
- TrustedTypePolicyFactory-createPolicy-unenforced.html (在线测试) (源码)
- TrustedTypePolicyFactory-defaultPolicy.html (在线测试) (源码)
- TrustedTypePolicyFactory-getAttributeType-namespace.html (在线测试) (源码)
- TrustedTypePolicyFactory-getAttributeType-svg.html (在线测试) (源码)
- TrustedTypePolicyFactory-getAttributeType.html (在线测试) (源码)
- TrustedTypePolicyFactory-isXXX.html (在线测试) (源码)
- Window-TrustedTypes.html (live test) (源码)
- Window-block-eval-function-constructor.html (在线测试) (源码)
- Window-setTimeout-setInterval.html (在线测试) (源码)
- block-Document-execCommand.html (在线测试) (源码)
- block-string-assignment-to-DOMParser-parseFromString.html (在线测试) (源码)
- block-string-assignment-to-DedicatedWorker-setTimeout-setInterval.html (在线测试) (源码)
- block-string-assignment-to-Document-parseHTMLUnsafe.html (在线测试) (源码)
- block-string-assignment-to-Document-write.html (在线测试) (源码)
- block-string-assignment-to-Element-insertAdjacentHTML.html (在线测试) (源码)
- block-string-assignment-to-Element-outerHTML.html (在线测试) (源码)
- block-string-assignment-to-Element-setAttribute.html (在线测试) (源码)
- block-string-assignment-to-Element-setAttributeNS.html (在线测试) (源码)
- block-string-assignment-to-Element-setHTMLUnsafe.html (在线测试) (源码)
- block-string-assignment-to-HTMLElement-generic.html (在线测试) (源码)
- block-string-assignment-to-HTMLIFrameElement-srcdoc.html (在线测试) (源码)
- block-string-assignment-to-Range-createContextualFragment.html (在线测试) (源码)
- block-string-assignment-to-ShadowRoot-innerHTML.html (在线测试) (源码)
- block-string-assignment-to-ShadowRoot-setHTMLUnsafe.html (在线测试) (源码)
- block-string-assignment-to-SharedWorker-setTimeout-setInterval.html (在线测试) (源码)
- block-string-assignment-to-Window-setTimeout-setInterval.html (在线测试) (源码)
- block-string-assignment-to-attribute-via-attribute-node.html (在线测试) (源码)
- block-string-assignment-to-text-and-url-sinks.html (在线测试) (源码)
- block-text-node-insertion-into-script-element.html (在线测试) (源码)
- block-text-node-insertion-into-svg-script-element.html (在线测试) (源码)
- csp-block-eval.html (live test) (源码)
- default-policy-callback-arguments.html (在线测试) (源码)
- default-policy-report-only.html (在线测试) (源码)
- default-policy.html (live test) (源码)
- empty-default-policy-report-only.html (在线测试) (源码)
- empty-default-policy.html (在线测试) (源码)
- eval-csp-no-tt.html (live test) (源码)
- eval-csp-tt-default-policy-mutate.html (在线测试) (源码)
- eval-csp-tt-default-policy.html (在线测试) (源码)
- eval-csp-tt-no-default-policy.html (在线测试) (源码)
- eval-function-constructor-untrusted-arguments-and-applying-default-policy.html (在线测试) (源码)
- eval-function-constructor-untrusted-arguments-and-default-policy-throwing.html (在线测试) (源码)
- eval-function-constructor.html (在线测试) (源码)
- eval-no-csp-no-tt-default-policy.html (在线测试) (源码)
- eval-no-csp-no-tt.html (live test) (源码)
- eval-with-permissive-csp.html (在线测试) (源码)
- get-trusted-types-compliant-attribute-value.html (在线测试) (源码)
- idlharness.window.js (live test) (源码)
- inheriting-csp-for-local-schemes.html (在线测试) (源码)
- legacy-trusted-script-urls.html (在线测试) (源码)
- legacy-trusted-scripts.html (在线测试) (源码)
- modify-attributes-in-callback.html (在线测试) (源码)
- no-require-trusted-types-for-report-only.html (在线测试) (源码)
- no-require-trusted-types-for.html (在线测试) (源码)
- require-trusted-types-for-TypeError-belongs-to-the-global-object-realm.html (在线测试) (源码)
- require-trusted-types-for-report-only.html (在线测试) (源码)
- require-trusted-types-for.html (在线测试) (源码)
- script-enforcement-001-outerHTML.xhtml (在线测试) (源码)
- script-enforcement-001.html (在线测试) (源码)
- script-enforcement-002-outerHTML.xhtml (在线测试) (源码)
- script-enforcement-002.html (在线测试) (源码)
- script-enforcement-003.html (在线测试) (源码)
- script-enforcement-004.html (在线测试) (源码)
- script-enforcement-005.html (在线测试) (源码)
- script-enforcement-006.html (在线测试) (源码)
- script-enforcement-007.html (在线测试) (源码)
- script-enforcement-008.https.html (在线测试) (源码)
- script-enforcement-009.https.html (在线测试) (源码)
- script-enforcement-010.html (在线测试) (源码)
- script-enforcement-011.html (在线测试) (源码)
- set-attributes-no-require-trusted-types.html (在线测试) (源码)
- set-attributes-require-trusted-types-default-policy.html (在线测试) (源码)
- set-attributes-require-trusted-types-no-default-policy.html (在线测试) (源码)
- should-sink-type-mismatch-violation-be-blocked-by-csp-001.html (在线测试) (源码)
- should-sink-type-mismatch-violation-be-blocked-by-csp-002-worker.html (在线测试) (源码)
- should-sink-type-mismatch-violation-be-blocked-by-csp-003.html (在线测试) (源码)
- should-trusted-type-policy-creation-be-blocked-by-csp-001.html (在线测试) (源码)
- should-trusted-type-policy-creation-be-blocked-by-csp-002.html (在线测试) (源码)
- should-trusted-type-policy-creation-be-blocked-by-csp-003.html (在线测试) (源码)
- should-trusted-type-policy-creation-be-blocked-by-csp-004-worker.html (在线测试) (源码)
- should-trusted-type-policy-creation-be-blocked-by-csp-005.html (在线测试) (源码)
- trusted-types-createHTMLDocument.html (在线测试) (源码)
- trusted-types-duplicate-names-list-report-only.html (在线测试) (源码)
- trusted-types-duplicate-names-list.html (在线测试) (源码)
- trusted-types-duplicate-names-without-enforcement.html (在线测试) (源码)
- trusted-types-duplicate-names.html (在线测试) (源码)
- trusted-types-eval-reporting-no-unsafe-eval.html (在线测试) (源码)
- trusted-types-eval-reporting-report-only.html (在线测试) (源码)
- trusted-types-event-handlers.html (在线测试) (源码)
- trusted-types-navigation.html (在线测试) (源码)
- trusted-types-report-only.html (在线测试) (源码)
- trusted-types-reporting-check-report-DedicatedWorker-create-policy.html (在线测试) (源码)
- trusted-types-reporting-check-report-DedicatedWorker-sink-mismatch.html (在线测试) (源码)
- trusted-types-reporting-check-report-Window-create-policy.html (在线测试) (源码)
- trusted-types-reporting-check-report-Window-sink-mismatch.html (在线测试) (源码)
- trusted-types-reporting-clipping-of-sample.html (在线测试) (源码)
- trusted-types-reporting-for-DOMParser-parseFromString.html (在线测试) (源码)
- trusted-types-reporting-for-DedicatedWorker-DedicatedWorker-constructor.html (在线测试) (源码)
- trusted-types-reporting-for-DedicatedWorker-ServiceWorkerContainer-register.https.html (在线测试) (源码)
- trusted-types-reporting-for-DedicatedWorker-eval.html (在线测试) (源码)
- trusted-types-reporting-for-DedicatedWorker-function-constructor.html (在线测试) (源码)
- trusted-types-reporting-for-DedicatedWorker-importScripts.html (在线测试) (源码)
- trusted-types-reporting-for-DedicatedWorker-setTimeout-setInterval.html (在线测试) (源码)
- trusted-types-reporting-for-Document-execCommand.html (在线测试) (源码)
- trusted-types-reporting-for-Document-parseHTMLUnsafe.html (在线测试) (源码)
- trusted-types-reporting-for-Document-write.html (在线测试) (源码)
- trusted-types-reporting-for-Element-innerHTML.html (在线测试) (源码)
- trusted-types-reporting-for-Element-insertAdjacentHTML.html (在线测试) (源码)
- trusted-types-reporting-for-Element-outerHTML.html (在线测试) (源码)
- trusted-types-reporting-for-Element-setAttribute.html (在线测试) (源码)
- trusted-types-reporting-for-Element-setHTMLUnsafe.html (在线测试) (源码)
- trusted-types-reporting-for-HTMLIFrameElement-srcdoc.html (在线测试) (源码)
- trusted-types-reporting-for-HTMLScriptElement-children-change.html (在线测试) (源码)
- trusted-types-reporting-for-HTMLScriptElement-innerHTML.html (在线测试) (源码)
- trusted-types-reporting-for-HTMLScriptElement.html (在线测试) (源码)
- trusted-types-reporting-for-Range-createContextualFragment.html (在线测试) (源码)
- trusted-types-reporting-for-SVGScriptElement-children-change.html (在线测试) (源码)
- trusted-types-reporting-for-SVGScriptElement-innerHTML.html (在线测试) (源码)
- trusted-types-reporting-for-ServiceWorker-ServiceWorkerContainer-register.https.html (在线测试) (源码)
- trusted-types-reporting-for-ServiceWorker-eval.https.html (在线测试) (源码)
- trusted-types-reporting-for-ServiceWorker-function-constructor.https.html (在线测试) (源码)
- trusted-types-reporting-for-ServiceWorker-importScripts.https.html (在线测试) (源码)
- trusted-types-reporting-for-ServiceWorker-setTimeout-setInterval.https.html (在线测试) (源码)
- trusted-types-reporting-for-ShadowRoot-innerHTML.html (在线测试) (源码)
- trusted-types-reporting-for-ShadowRoot-setHTMLUnsafe.html (在线测试) (源码)
- trusted-types-reporting-for-SharedWorker-DedicatedWorker-constructor.html (在线测试) (源码)
- trusted-types-reporting-for-SharedWorker-ServiceWorkerContainer-register.https.html (在线测试) (源码)
- trusted-types-reporting-for-SharedWorker-eval.html (在线测试) (源码)
- trusted-types-reporting-for-SharedWorker-function-constructor.html (在线测试) (源码)
- trusted-types-reporting-for-SharedWorker-importScripts.html (在线测试) (源码)
- trusted-types-reporting-for-SharedWorker-setTimeout-setInterval.html (在线测试) (源码)
- trusted-types-reporting-for-Window-DedicatedWorker-constructor.html (在线测试) (源码)
- trusted-types-reporting-for-Window-ServiceWorkerContainer-register.https.html (在线测试) (源码)
- trusted-types-reporting-for-Window-SharedWorker-constructor.html (在线测试) (源码)
- trusted-types-reporting-for-Window-eval.html (在线测试) (源码)
- trusted-types-reporting-for-Window-function-constructor.html (在线测试) (源码)
- trusted-types-reporting-for-Window-setTimeout-setInterval.html (在线测试) (源码)
- trusted-types-reporting.html (在线测试) (源码)
- trusted-types-sandbox-allow-scripts.html (在线测试) (源码)
- trusted-types-sandbox-no-allow-scripts.html (在线测试) (源码)
- trusted-types-source-file-path.html (在线测试) (源码)
- trusted-types-svg-script-set-href.html (在线测试) (源码)
- trusted-types-tojson.html (在线测试) (源码)
- tt-block-eval.html (live test) (源码)
1. 介绍
本节为非规范内容。
某些类型的安全漏洞,当 Web 应用程序从攻击者可控的来源(例如文档 URL 参数或 postMessage 通道)获取值,并在未经适当净化的情况下,将该值传递给某个注入点(具有强大功能的各种 Web API 函数)时,就会发生。
此类问题传统上很难防范。应用通常以攻击者可控的值调用这些注入点,而作者并未意识到,因为在调用注入点时,并不清楚输入是否由攻击者控制。同时,由于 JavaScript
的动态特性,很难确定程序中是否存在这种模式。这常被手动代码审查和自动化代码分析所遗漏。例如,如果 aString 包含不受信任的数据,则
foo[bar] = aString 这一语句就有可能(取决于 foo 和 bar 的值)导致安全漏洞。
本文档聚焦于防止 DOM 型跨站脚本攻击(DOM XSS),这种攻击发生在攻击者控制的数据到达§ 2.1.1 DOM XSS
注入点时,因为最终会导致执行攻击者控制的脚本。DOM XSS 在 Web 应用中广泛存在,有 60 多种注入点(如 Element.innerHTML 或
Location.href 等设值方法)。
本文定义了受信任类型(Trusted Types)——一种允许应用把注入点锁定为仅接受不可伪造的带类型值(替代字符串)的 API。这些值只能由应用自定义的策略创建,使得作者能够为危险 API 设定规则,只需保护 Web 应用代码中的极小部分,这些部分容易被安全防护、监控和审查,从而大大减少了攻击面。
1.1. 目标
-
尽可能减少在以不受信任数据调用强大 Web API 时出现客户端安全漏洞的可能性,例如,降低 DOM XSS 的发生概率。
-
鼓励安全决策被封装在应用中的小范围部分。
-
减少复杂 Web 应用代码库的安全审查量。
-
像常规编程错误一样利于开发者检测和暴露漏洞,比如借助动态和静态分析工具辅助检测。
1.2. 非目标
-
防止或减轻服务端生成标记(markup)被注入的后果,特别是脚本正文反射到文档中。对于服务端 XSS,推荐使用模板系统或 CSP script-src 等方案。
-
解决资源约束(如防止数据泄漏或通过 [Fetch] 连接外部资源)。
-
控制子资源加载。受信任类型的目的是让作者能控制可对当前文档进行脚本的资源加载,而非其它子资源。
-
防止 跨域 JavaScript 执行(比如 Trusted Types 不会防范通过
data:URL 加载带脚本的新文档)。 -
防止恶意 Web 应用作者绕过限制;试图防御恶意作者会导致设计过于复杂,不切实际。
1.3. 使用场景
-
作者维护了一个由框架生成 UI 组件的复杂 Web 应用,该框架使用安全模板系统。应用还依赖第三方客户端库(如分析、性能监控等)。为了确保这些组件都不引入 DOM XSS 漏洞,作者在模板库中定义了 Trusted Type 策略并对 § 2.1.1 DOM XSS 注入点 启用强制执行。
-
某网站使用 § 2.1.1 DOM XSS 注入点。网站开发者添加受信任类型并通过 Content-Security-Policy-Report-Only 响应头监控违规。通过重构代码,只用安全方法,逐步修复违规点。最终,调用 § 2.1.1 DOM XSS 注入点 的地方都被清除,因此不再需要受信任类型。开发者关闭只报告模式并用 trusted-types 和 require-trusted-types-for 指令禁用策略。重构期间网站功能始终未受影响。
-
一个大型团队维护复杂的客户端应用。他们创建了一些能满足安全要求的 Trusted Types 策略。团队把这些策略实现和安全抽象统一到极少量、安全审查严格的文件,并要求这些文件的提交需要额外审批。
由于需要通过安全抽象才能影响注入点,并且相关代码受到重点审查,开发者更倾向于用安全抽象而不是随手拼接字符串去操作 § 2.1.1 DOM XSS 注入点。
安全审计人员评估 DOM XSS 风险时,发现仅需关注极小攻击面:即 CSP 响应头和安全抽象代码,无需处理大部分客户端代码。
-
某现有 Web 应用主要用 XSS 安全模式与 DOM 交互(未用 § 2.1.1 DOM XSS 注入点),但有少数场所用到了如 JSONP 加载脚本、调用
innerHTML或eval等高风险方式。经检查,这些地方不会引发 XSS(如无用户控制数据输入),但很难彻底迁移掉这类用法。
因此,无法对应用启用 CSP(除非勉强用
'unsafe-eval' 'unsafe-inline')。而且,代码库可能遗漏了带 DOM XSS 漏洞的代码,或将来引入新的漏洞。为降低风险,作者将已检查代码改用 Trusted Types 并启用其强制执行。将来如果有其它地方用到注入点,也能被正确拦截和报告。
-
安全团队负责确保客户端主导的应用无 XSS 漏洞。因服务端代码简单(主要为 API 后端),且应用强制启用 Trusted Types,审查的重点只需关注受信任类型策略及其规则。随后,只允许已检查的策略名被包含在 'trusted-types' CSP 指令中,开发者可安全使用。
除非某段代码创建 Trusted Type 策略,其它代码(包含常变依赖)可免审查。不创建策略就无法导致 DOM XSS。
2. 框架
2.1. 注入点
本节为非规范内容。
注入点是一类只能用受信任、通过验证或适当净化的输入调用的强大 Web API 函数。用攻击者可控(即注入)的输入调用注入点可能导致不良后果,属于安全漏洞。
注: 本文所涵盖注入点的具体清单见 § 4 集成。
仅分析注入点的调用(通常是字符串输入),很难判断某个应用是否具有这类漏洞(比如是否易受 DOM XSS
攻击)。例如,应用可能本就要用动态生成的输入调用 eval() 来做代码混淆,但如果输入可被攻击者控制,就是安全漏洞——实际用例很难区分。
本文将注入点分组,按照每组所具备的能力。各组的强制执行由trusted-types-sink-group 值控制。
2.1.1. DOM XSS 注入点
本节为非规范内容。
DOM XSS 注入点以可能导致 DOM XSS 的方式处理输入字符串值(如果该值不可信)。
示例包括:
-
可用于加载代码 URL 的
Element属性设值器,如HTMLScriptElement.src -
可执行代码的
Element属性设值器,如HTMLScriptElement.text -
直接执行代码的函数,如
eval, -
导航到 'javascript:' URL。
由于 HTML 解析器可创建任意元素(含脚本)并设任意属性,DOM XSS 注入点还包括 HTML 解析点:
-
将 HTML 字符串解析并插入文档的函数,如
Element.innerHTML、ShadowRoot.innerHTML、 和Element.outerHTML设值器,或 Document.write。 -
创建包含调用者控制标记的新同源
Document的函数,如parseFromString()
守护 DOM XSS 注入点的开关由名为 'script' 的 trusted-types-sink-group 控制。
2.2. 受信任类型
为了让作者能把控流向注入点的值, 我们引入 § 2.2 受信任类型。以下列出了 受信任类型,表明作者信任某个值可在特定场景下被用作注入点的输入。
注: 这里的受信任指的是应用作者确信该值可安全用于注入点——她信任此值不会引漏洞,并不代表值本身绝对安全。
注: 这允许作者在创建某个值时明确意图,浏览器可基于该类型实施检查以保护作者的意图。举例而言,如果值本意用作 HTML 片段,用作加载脚本就会失败。
注: 所有受信任类型都包裹着不可变字符串,对象创建时指定。对象本身不可伪造:JS 无法篡改其内部字符串值,仅在内部插槽保存,未提供 setter。
注: 所有受信任类型的字符串化操作都会返回内部字符串值。这便于应用代码逐步从 DOM 字符串迁移到 Trusted Types(可局部生产类型,代码其他部分仍可用字符串)。因此,受信任类型与常规 DOM API 向后兼容。
2.2.1. TrustedHTML
TrustedHTML 接口代表开发者可放心插入到注入点(会当作 HTML 渲染)的字符串。这是包裹字符串的不可变对象,通过 TrustedTypePolicy
的
createHTML
方法构造。
[Exposed =(Window ,Worker )]interface TrustedHTML {stringifier ;DOMString toJSON (); };
TrustedHTML 对象有个关联字符串 data。 此值在对象创建时设定,生命周期内不变。
toJSON() 方法和
字符串化行为 都应返回关联的 data 值。
2.2.2. TrustedScript
TrustedScript 接口代表开发者可放心传递给注入点(很可能会执行该脚本)的、未编译脚本正文的字符串。该对象是不可变的字符串包装,通过 TrustedTypePolicy
的
createScript
方法构造。
[Exposed =(Window ,Worker )]interface TrustedScript {stringifier ;DOMString toJSON (); };
TrustedScript 对象有个关联字符串 data。 此值在对象创建时设定,生命周期内不变。
toJSON() 方法和
字符串化行为 都应返回关联的 data 值。
2.2.3. TrustedScriptURL
TrustedScriptURL 接口代表开发者可放心传递给注入点(并以外部脚本资源 URL 解析)的字符串。这类对象是不可变的字符串包装,通过 TrustedTypePolicy
的
createScriptURL
方法构造。
[Exposed =(Window ,Worker )]interface TrustedScriptURL {stringifier ;USVString toJSON (); };
TrustedScriptURL 对象有个关联字符串 data。 此值在对象创建时设定,生命周期内不变。
toJSON() 方法和
字符串化行为 都应返回关联的 data 值。
2.3. 策略
受信任类型只能通过用户自定义、不可变的策略创建。策略定义将字符串转化为特定受信任类型对象的规则。策略允许作者根据需求定制受信任类型遵循的编程规则。
TrustedHTML
对象都可安全地在应用中使用(如传递给 innerHTML 设值器)——即使输入值由攻击者控制,策略规则已将其中和成安全内容。
const sanitizingPolicy= trustedTypes. createPolicy( 'sanitize-html' , { createHTML: ( input) => myTrustedSanitizer( input, { superSafe: 'ok' }), }); myDiv. innerHTML= sanitizingPolicy. createHTML( untrustedValue);
注: 受信任类型对象用来包裹作者明确信任的值。因此,创建受信任类型对象实例本身就成为事实上的注入点,代码中的此过程也极为安全敏感。为严格控制对象的创建,相关构造方法不直接暴露,而要求必须通过策略创建。
同一范围(Realm)中可创建多个策略,应用可对不同代码部分定义不同规则。
const cdnScriptsPolicy= trustedTypes. createPolicy( 'cdn-scripts' , { createScriptURL( url) { const parsed= new URL( url, document. baseURI); if ( parsed. origin== 'https://mycdn.example' ) { return url; } throw new TypeError ( 'invalid URL' ); }, }); myLibrary. init({ policy: cdnScriptsPolicy});
注: 受信任类型对象只能通过策略创建。如果强制执行已启用,只有策略代码能触发注入点动作,因此策略的 create*
方法调用处是全程序唯一安全敏感点,无需监控所有注入点。User Agent 会强制注入点只接受匹配的受信任类型对象,而这些对象只能经策略创建。
createPolicy
方法返回一个策略对象,create* 方法会按策略规则创建受信任类型对象。
注:
对于能净化输入的策略,可在应用任意处自由使用。但有时需要宽松策略且仅供内部调用,必须确保仅用作者可控输入。例如,客户端 HTML 模板库、HTML 净化库或 JS 异步代码插件加载系统可能都需完全控制 HTML 或
URL。API 也支持这点:只有调用方获得策略引用(createPolicy()
返回值)时才能用策略。策略引用就是能力,JS
可用闭包、函数内变量或模块限制访问。
( function renderFootnote() { const unsafePolicy= trustedTypes. createPolicy( 'html' , { createHTML: input=> input, }); const footnote= await fetch( '/footnote.html' ). then( r=> r. text()); footNote. innerHTML= unsafePolicy. createHTML( footnote); })();
2.3.1.
TrustedTypePolicyFactory
TrustedTypePolicyFactory 用于创建
策略
并验证受信任类型对象实例是否是通过这些策略创建的。
注: 该工厂对象通过全局对象上的 trustedTypes 属性暴露给
JavaScript —— 详见 § 4.1.1 窗口或 Worker
全局作用域接口的扩展。
[Exposed =(Window ,Worker )]interface TrustedTypePolicyFactory {TrustedTypePolicy createPolicy (DOMString ,policyName optional TrustedTypePolicyOptions = {});policyOptions boolean isHTML (any );value boolean isScript (any );value boolean isScriptURL (any );value readonly attribute TrustedHTML emptyHTML ;readonly attribute TrustedScript emptyScript ;DOMString ?getAttributeType (DOMString ,tagName DOMString ,attribute optional DOMString ?= "",elementNs optional DOMString ?= "");attrNs DOMString ?getPropertyType (DOMString ,tagName DOMString ,property optional DOMString ?= "");elementNs readonly attribute TrustedTypePolicy ?defaultPolicy ; };
A TrustedTypePolicyFactory
对象有一个关联的 TrustedTypePolicy
默认策略。
初始值为 null。
A TrustedTypePolicyFactory
对象有一个关联的字符串有序集合已创建的策略名称。
初始值为 « »。
createPolicy(policyName, policyOptions)-
创建一个策略对象,用于执行
TrustedTypePolicyOptionspolicyOptions 对象中传入的规则。 可允许的策略名称可能受 内容安全策略限制。 如果策略名称不在 trusted-types CSP 指令定义的白名单中, 则创建策略失败并抛出 TypeError。 此外,如果启用了唯一策略名称(即未使用'allow-duplicates'), 并且多次以相同policyName调用createPolicy, 也会导致策略创建失败并抛出 TypeError。// HTTP 响应头: Content-Security-Policy: trusted-types foo trustedTypes. createPolicy( "foo" , {}); // 正常 trustedTypes. createPolicy( "bar" , {}); // 抛出异常 - 名称不在白名单。 trustedTypes. createPolicy( "foo" , {}); // 抛出异常 - 名称重复。 返回执行创建受信任类型策略算法的结果, 并传入下列参数:
const myPolicy= trustedTypes. createPolicy( 'myPolicy' , { // 此安全敏感代码需要安全审核; // 代码缺陷可能导致 DOM XSS。 createHTML( input) { return aSanitizer. sanitize( input) }, createScriptURL( input) { const u= new URL( dirty, document. baseURI); if ( APPLICATION_CONFIG. scriptOrigins. includes( u. origin)) { return u. href; } throw new Error ( 'Cannot load scripts from this origin' ); }, }); document. querySelector( "#foo" ). innerHTML= myPolicy. createHTML( aValue); scriptElement. src= myPolicy. createScriptURL( 'https://scripts.myapp.example/script.js' ); isHTML(value)-
如果 value 是
TrustedHTML实例且其 data 有值,则返回 true,否则返回 false。注:
is*方法用于检查某对象是否真的是合法的 受信任类型对象 (即通过配置的策略创建)。这样能检测例如通过 Object.create 或原型链篡改伪造的对象。 isScript(value)-
如果 value 是
TrustedScript实例且其 data 有值,则返回 true,否则返回 false。 isScriptURL(value)-
如果 value 是
TrustedScriptURL实例且其 data 有值,则返回 true,否则返回 false。 getPropertyType(tagName, property, elementNs)-
允许作者检查指定
Element属性(IDL 属性)是否需要受信任类型。此函数按如下算法返回结果:
-
将 localName 设为 tagName 的ASCII 小写。
-
如果 elementNs 为 null 或空字符串,则设为HTML 命名空间。
-
令 interface 为 localName 和 elementNs 对应的元素接口。
-
令 expectedType 取 null。
-
在以下表格中找到与 interface 名称或 "*" 匹配,且属性名为 property 的行。若匹配,expectedType 设为第三列类型名。
元素 属性名 TrustedType HTMLIFrameElement"srcdoc" TrustedHTMLHTMLScriptElement"innerText" TrustedScriptHTMLScriptElement"src" TrustedScriptURLHTMLScriptElement"text" TrustedScriptHTMLScriptElement"textContent" TrustedScript"*" "innerHTML" TrustedHTML"*" "outerHTML" TrustedHTML -
返回 expectedType。
-
getAttributeType(tagName, attribute, elementNs, attrNs)-
允许作者检查指定
Element内容属性是否需要某种受信任类型,并确保后续Element.setAttribute能传入正确参数类型。此函数按如下算法返回结果:
-
将 localName 设为 tagName 的ASCII 小写。
-
将 attribute 设为 ASCII 小写。
-
如果 elementNs 为 null 或空字符串,则设为HTML 命名空间。
-
如果 attrNs 是空字符串,则设为 null。
-
令 interface 为 localName 和 elementNs 对应的元素接口。
-
令 expectedType 取 null。
-
将 attributeData 设为获取属性的受信任类型数据算法的结果,参数为:
-
interface 作为 element
-
attribute
-
attrNs
-
-
如果 attributeData 不为 null,则 expectedType 设为 attributeData 第4项的类型名。
-
返回 expectedType。
-
emptyHTML, 类型为 TrustedHTML, 只读-
为
TrustedHTML对象,其 data 值为空字符串。
emptyScript, 类型为 TrustedScript, 只读-
为
TrustedScript对象,其 data 值为空字符串。
注: 此对象可用于检测运行环境是否支持动态代码编译。
若原生 Trusted Types 实现支持 eval(TrustedScript),将实际执行代码并返回假值 undefined;
若无原生支持,eval(trustedTypes.emptyScript) 会返回一个真值对象,无法解包和执行代码,polyfill 无法模拟。
// 原生 Trusted Types 支持时,eval(trustedTypes.emptyScript) 执行并返回假值 undefined。 // 否则,eval(trustedTypes.emptyScript) 返回真值 Object。 const supportsTS= ! eval( trustedTypes. emptyScript); eval( supportsTS? myTrustedScriptObj: myTrustedScriptObj. toString());
defaultPolicy, 类型为 TrustedTypePolicy, 只读,可为 null-
返回 默认策略 的值。
2.3.2. TrustedTypePolicy
策略对象实现 TrustedTypePolicy 接口,并定义一组用于创建受信任类型对象的函数。每个 create* 函数会将字符串值转换为指定的受信任类型变体,如果不允许转换则抛出
TypeError。
[Exposed =(Window ,Worker )]interface TrustedTypePolicy {readonly attribute DOMString ;name TrustedHTML createHTML (DOMString ,input any ...);arguments TrustedScript createScript (DOMString ,input any ...);arguments TrustedScriptURL createScriptURL (DOMString ,input any ...); };arguments
每个策略有一个name(名称)。
每个 TrustedTypePolicy 对象有一个关联的 TrustedTypePolicyOptions
options 对象,描述策略的实际行为。
createHTML(input, ...arguments)-
返回执行创建受信任类型算法的结果,并传入如下参数:
- policy
- this 值
- trustedTypeName
"TrustedHTML"- value
- input
- arguments
- arguments
createScript(input, ...arguments)-
返回执行创建受信任类型算法的结果,并传入如下参数:
- policy
- this 值
- trustedTypeName
"TrustedScript"- value
- input
- arguments
- arguments
createScriptURL(input, ...arguments)-
返回执行创建受信任类型算法的结果,并传入如下参数:
- policy
- this 值
- trustedTypeName
"TrustedScriptURL"- value
- input
- arguments
- arguments
2.3.3.
TrustedTypePolicyOptions
该字典用于存放作者自定义的函数,将字符串值转换为受信任值。这些函数不会直接创建受信任类型
对象实例——实际对象创建行为是由
TrustedTypePolicy提供的。
dictionary TrustedTypePolicyOptions {CreateHTMLCallback ;createHTML CreateScriptCallback ;createScript CreateScriptURLCallback ; };createScriptURL callback =CreateHTMLCallback DOMString ? (DOMString ,input any ...);arguments callback =CreateScriptCallback DOMString ? (DOMString ,input any ...);arguments callback =CreateScriptURLCallback USVString ? (DOMString ,input any ...);arguments
2.3.4. 默认策略
本节为非规范内容。
其中有一个策略(其名称为
"default")是特殊的;
当某个注入点被传入字符串(而不是受信任类型对象)时,用户代理会以非受信字符串、注入点的受信任类型和注入点类型三个参数自动调用该策略。
这样,应用可以定义一个备用行为,以免直接导致违规。目的是让应用在出现意外数据流时能够补救,对潜在受攻击者控制的字符串做“最后的净化”,或者在无法创建安全值时拒绝该值。若策略内部抛出错误,则错误会上抛给应用。
如果不存在默认策略,或相应的 create* 函数返回 null 或 undefined ,则会导致 CSP
违规。在强制模式下会抛出错误,在仅报告模式下会继续使用传给默认策略的原始值。
注: 这一可选行为适用于那些还在用遗留注入点代码但想引入受信任类型强制的应用。需要强调的是,这个策略必须定义得非常严格,防止绕过安全限制。极端情况下,默认策略如果宽松无操作,那就彻底失去了 Trusted Types 的保护意义。因此,作者应仅在过渡期定义默认策略,用其发现和重构不安全使用注入点的依赖代码,并最终彻底弃用默认策略。
注: 默认策略的应用细节见 § 3.4 获取受信任类型合规字符串。
// Content-Security-Policy: trusted-types default; require-trusted-types-for 'script' trustedTypes. createPolicy( 'default' , { createScriptURL: ( value, type, sink) => { console. log( "Please refactor." ); return value+ '?default-policy-used&type=' + encodeURIComponent( type) + '&sink=' + encodeURIComponent( sink); } }); aScriptElement. src= "https://cdn.example/script.js" ; // Please refactor. console. log( aScriptElement. src); // https://cdn.example/script.js?default-policy-used&type=TrustedScriptURL&sink=HTMLScriptElement%20src
2.4. 强制
注: 强制是指在值进入注入点前检查其类型是否合规的过程。
允许作者创建策略及其受信任类型对象的 JavaScript API 始终可用(通过 trustedTypes)。
由于注入点会对安全敏感参数进行字符串化,受信任类型对象转换为其内部字符串,所以作者可用 Trusted
Types 替换字符串使用。
为了保护注入点,除了让 JS 使用受信任类型外,用户代理还需强制校验:即确保某组注入点绝不允许用字符串调用,必须用受信任类型。本节讲述了作者如何控制这一 enforcing 行为。
作者也可通过规定策略创建规则控制其策略。
2.4.1. 内容安全策略(Content Security Policy)
应用可通过配置内容安全策略来控制受信任类型的强制。本规范定义了与 Trusted Types 规则对应的新指令。 require-trusted-types-for 指令指定哪些注入点分组必须使用受信任类型。trusted-types 指令控制策略的创建方式。
注: 使用 CSP 机制可以让作者通过 Content-Security-Policy-Report-Only HTTP 响应头为应用即将强制 Trusted Types 做好准备。
注: 大多数强制规则都是对其它规范中算法的修改,见 § 4 集成。
3. 算法
3.1. 创建受信任类型策略
要创建受信任类型策略,给定TrustedTypePolicyFactory
(factory)、字符串 (policyName)、TrustedTypePolicyOptions
字典 (options) 和
全局对象 (global),执行以下步骤:
-
令 allowedByCSP 为执行 内容安全策略是否应阻止受信任类型策略创建算法的结果,参数为 global、policyName 和 factory 的 已创建策略名称 值。
-
若 allowedByCSP 为
"Blocked",抛 TypeError 并终止后续步骤。 -
若 policyName 为
default且 factory 的 默认策略 不为 null,则抛 TypeError 并终止后续步骤。 -
令 policy 为新的
TrustedTypePolicy对象。 -
设 policy 的
name属性为 policyName。 -
设 policy 的 options 为 «[ "createHTML" -> options["
createHTML"], "createScript" -> options["createScript"], "createScriptURL" -> options["createScriptURL"] ]»。 -
若 policyName 为
default,设 factory 的 默认策略为 policy。 -
返回 policy。
3.2. 创建受信任类型
要创建受信任类型,给定TrustedTypePolicy
policy、类型名 trustedTypeName、字符串 value 和参数列表 arguments,执行如下步骤:
-
令 policyValue 为执行获取受信任类型策略值算法的结果,参数同本算法,并多传 true 为 throwIfMissing。
-
如该算法抛出错误,则重新抛出错误并终止后续步骤。
-
令 dataString 为 policyValue 的字符串化结果。
-
如 policyValue 为 null 或 undefined,则 dataString 设为 ""。
-
返回一个类型名为 trustedTypeName 的新接口对象,其数据值设为 dataString。
3.3. 获取受信任类型策略值
要获取受信任类型策略值,给定TrustedTypePolicy
policy、类型名 trustedTypeName、字符串 value、参数列表 arguments 及布尔
throwIfMissing,执行如下步骤:
-
令 functionName 为如下表给定 trustedTypeName 的函数名:
函数名 受信任类型名 "createHTML" "TrustedHTML" "createScript" "TrustedScript" "createScriptURL" "TrustedScriptURL" -
令 function 为 policy 的 options[functionName]。
-
若 function 为
null,则:-
如 throwIfMissing,抛 TypeError。
-
否则,返回
null。
-
-
令 args 为 « value »。
-
追加参数 arguments 每项至 args。
-
令 policyValue 为 调用 function 并传参 args 及
"rethrow"的结果。 -
返回 policyValue。
3.4. 获取受信任类型合规字符串
此算法将返回可用于注入点的字符串,可选自动从匹配的受信任类型解包。 它将确保受信任类型的强制规则得到遵守。
要获取受信任类型合规字符串,给定TrustedType
类型(expectedType)、全局对象(global)、
TrustedType
或字符串(input)、字符串(sink)、字符串(sinkGroup),按如下步骤运行:
-
如果 input 是 expectedType 的实例,则返回 input 的字符串化结果并终止。
-
令 requireTrustedTypes 为执行接收类型是否需要受信任类型?算法的结果, 参数为 global、sinkGroup、true。
-
如果 requireTrustedTypes 为
false,返回 input 的字符串化结果并终止。 -
令 convertedInput 为执行通过默认策略处理值算法的结果,参数同本算法。
-
如果算法抛出错误,重新抛出该错误并终止后续步骤。
-
如果 convertedInput 为
null或undefined,执行以下步骤:-
令 disposition 为执行内容安全策略是否应阻止类型不匹配违规?算法的结果, 参数为 global、input 的字符串化、sinkGroup 和 sink。
-
如果 disposition 为
“Allowed”,返回 input 的字符串化结果并终止。注: 此步骤确保默认策略拒绝会被报告,但只报告模式下会被忽略。
-
抛出 TypeError 并终止。
-
-
断言:convertedInput 是 expectedType 的实例。
-
返回 convertedInput 的字符串化结果。
3.5. 通过默认策略处理值
此算法将值通过默认策略分发给注入点,如果有默认策略的话。
要通过默认策略处理值,给定 TrustedType
类型(expectedType)、全局对象(global)、
TrustedType
或字符串(input)、字符串(sink),按如下步骤运行:
-
令 policyValue 为执行获取受信任类型策略值算法的结果,参数为:
-
defaultPolicy 作为 policy
-
input 的字符串化作为 value
-
expectedType 的类型名作为 trustedTypeName
-
« trustedTypeName, sink » 作为 arguments
-
false 作为 throwIfMissing
-
-
如果算法抛出错误,重新抛出该错误并终止。
-
如果 policyValue 为 null 或 undefined,返回 policyValue。
-
令 dataString 为 policyValue 的字符串化结果。
-
返回类型名为 trustedTypeName 的新接口实例,其关联数据值为 dataString。
3.6. 准备脚本文本
要准备脚本文本,给定一个
HTMLScriptElement
或 SVGScriptElement
(script),执行下列步骤:
-
如果 script 是
HTMLScriptElement,则令 sink 为 "HTMLScriptElement text";否则为 "SVGScriptElement text"。 -
如果 script 的 script text 与其子文本内容不同, 则将 script 的 script text 设为执行获取受信任类型合规字符串算法的结果,参数为:
-
TrustedScriptURL作为 expectedType, -
script 的子文本内容属性值作为 input,
-
sink,
-
'script'作为 sinkGroup。
如果算法抛出错误,则重新抛出错误。
-
3.7. 获取受信任类型合规属性值
要获取受信任类型合规属性值,给定字符串 attributeName、字符串
attributeNs、Element
element 和 TrustedType
或字符串 newValue,按以下步骤执行:
-
如果 attributeNs 为空字符串,则将 attributeNs 设为 null。
-
令 attributeData 为执行获取属性的受信任类型数据算法的结果,参数为:
-
element
-
attributeName
-
attributeNs
-
-
如果 attributeData 为 null,则:
-
如果 newValue 是字符串,返回 newValue。
-
断言:newValue 是
TrustedHTML或TrustedScript或TrustedScriptURL。 -
返回 value 的关联数据。
-
-
令 expectedType 为 attributeData 的第4项的值。
-
令 sink 为 attributeData 的第5项的值。
-
返回执行获取受信任类型合规字符串算法的结果,参数为:
如算法抛出错误,则重新抛出错误。
3.8. 获取属性的受信任类型数据
要获取属性的受信任类型数据,给定 element、attribute、attributeNs,执行下列步骤:
下文用到的 事件处理器内容属性概念语义暧昧。本规范需要更好机制识别事件处理器属性。详见 https://github.com/w3c/trusted-types/issues/520。
-
令 data 为 null。
-
如果 attributeNs 为 null,且 « HTML 命名空间, SVG 命名空间, MathML 命名空间 » 包含 element 的命名空间,且 attribute 是事件处理器内容属性名:
-
返回 (
Element, null, attribute,TrustedScript, "Element " + attribute)。
-
-
在下表中查找 element 在第一列、attributeNs 在第二列、attribute 在第三列的行; 若有匹配,设 data 为该行。
Element 属性命名空间 属性局部名 TrustedType Sink HTMLIFrameElementnull "srcdoc" TrustedHTML"HTMLIFrameElement srcdoc" HTMLScriptElementnull "src" TrustedScriptURL"HTMLScriptElement src" SVGScriptElementnull "href" TrustedScriptURL"SVGScriptElement href" SVGScriptElementXLink 命名空间 "href" TrustedScriptURL"SVGScriptElement href" -
返回 data。
4. 集成
typedef (TrustedHTML or TrustedScript or TrustedScriptURL );TrustedType
4.1. 与 HTML 的集成
Window
和 Worker
对象有 受信任类型策略工厂,
其类型为 TrustedTypePolicyFactory。
4.1.1. WindowOrWorkerGlobalScope 接口扩展
本文档扩展了 WindowOrWorkerGlobalScope
接口,定义见 HTML:
partial interface mixin WindowOrWorkerGlobalScope {readonly attribute TrustedTypePolicyFactory ; };trustedTypes
trustedTypes
getter 步骤是返回 this
的 相关全局对象 的 trusted
type policy factory。
4.1.2. 脚本中的强制
本文档修改了 HTMLScriptElement
的子文本内容的设置方式,使应用可以控制动态创建的脚本。
具体做法是在 innerText
和 textContent
属性直接加到 HTMLScriptElement
上。
除调用获取受信任类型合规字符串的附加行为外,这些属性的行为与原本一致。
注: 动态设置脚本的 URL 或文本推荐直接用这些 IDL 属性。直接操作属性节点或文本节点时,脚本准备阶段会对最终值调用默认策略。
partial interface HTMLScriptElement { [CEReactions ]attribute (TrustedScript or [LegacyNullToEmptyString ]DOMString ); [innerText CEReactions ]attribute (TrustedScript or DOMString )?; [textContent CEReactions ]attribute (TrustedScriptURL or USVString ); [src CEReactions ]attribute (TrustedScript or DOMString ); };text
4.1.2.1. 带受信任值的插槽
HTMLScriptElement
和 SVGScriptElement
拥有:
- 相关字符串 script text(脚本文本)。
-
一个字符串,用于保存符合要求的脚本主体(通过合规注入点设置)。等价于 script 的子文本内容。初始值为空字符串。
4.1.2.2.
innerText
IDL 属性
innerText
的 setter 步骤如下:
-
令 value 为调用 获取可信类型兼容字符串,参数为
TrustedScript、 此对象的 相关全局对象、给定值、HTMLScriptElement innerText和script后的结果。 -
将 此对象的 script text 值设置为 value。
-
使用 设置 inner text 步骤,参数为 此对象 和 value,运行之。
innerText
的 getter 步骤如下:
4.1.2.3.
textContent
IDL 属性
textContent
setter 步骤如下:如果给定值为 null,则按空字符串处理,然后执行如下描述:
-
令 value 为调用 获取可信类型兼容字符串,参数为
TrustedScript、 此对象的 相关全局对象、给定值、HTMLScriptElement textContent和script后的结果。 -
将 此对象的 script text 值设置为 value。
-
使用 设置 text content 步骤,参数为 此对象 和 value,运行之。
textContent
getter 步骤如下:
-
返回调用 get text content,参数为 this 的结果。
注: 目前我们未为 SVGScriptElement
添加等效内容。
详见 https://github.com/w3c/trusted-types/issues/512。
4.1.2.4.
text
IDL 属性
如下更新 text
setter 步骤算法。
-
令 value 为调用 获取受信任类型合规字符串 的结果,参数为
TrustedScript, this 的 相关全局对象,给定值,HTMLScriptElement text和script。 - 将 this 的 script text 设为给定值。
4.1.2.5.
src
IDL 属性
src
getter 步骤如下:
- 令 element 为调用 this 的“获取 element” 的结果。
- 令 contentAttributeValue 为调用 this 的“获取 content attribute” 的结果。
- 如果 contentAttributeValue 为 null,则返回空字符串。
- 令 urlString 为对 contentAttributeValue 以 element 的节点文档为基准编码、解析和序列化 URL 的结果。
- 如果 urlString 不为 failure,则返回 urlString。
- 返回将 contentAttributeValue 转为标量值字符串的结果。
src
setter 步骤如下:
-
令 value 为调用 获取受信任类型合规字符串 的结果,参数为
TrustedScriptURL, this 的 相关全局对象,给定值,HTMLScriptElement src和script。 - 将 this 的 src content attribute 设为 value。
4.1.2.6. 从解析器设置插槽值
本文档修改了 HTML 解析器,以在脚本创建时设置 script text 值。
如下修改 文本插入模式算法:
- 标签名为 "script" 的结束标签
-
...
将 script 的 script text 设为其 子文本内容。
如果 活动的推测性 HTML 解析器 为 null,则 准备脚本元素 script。这样可能会执行一些脚本,也可能会导致 新字符被插入到分词器,从而分词器输出更多 token,导致解析器重入调用。
...
上述算法未考虑脚本元素内容在解析过程中被更改的情况。实现者必须确保防范该场景,详见 https://github.com/w3c/trusted-types/issues/507。
尚无 SVG 脚本元素处理的规范定义。但各实现必须对
SVGScriptElement
处理做类似变更。
4.1.2.7. 插槽值校验
如下修改 准备脚本元素算法的前几步:
-
如果 el 的 already started 为 true,则返回。
-
令 parser document 为 el 的 parser document。
-
将 el 的 parser document 设为 null。
这样做的目的是,如果解析器尝试运行的 parser-inserted
script元素运行失败(例如为空或指定了不支持的脚本语言),之后其他脚本可变更其内容并再次运行。 -
若 parser document 非 null 且 el 未含有
async属性,则将 el 的 force async 设为 true。这样做的目的是,如果 parser-inserted
script元素解析器尝试执行时失败,而之后通过脚本动态修改再执行,依然会异步运行,即使未设置async属性。 -
对 el 执行 准备脚本文本算法。如果抛错,则返回。
-
令 source text 为 el 的
子文本内容script text 的值。 - ...
尚无 SVG
脚本元素处理的规范定义。但各实现必须对 SVGScriptElement
做类似变更。
4.2. 与 DOM 的集成
注: 详见 https://github.com/whatwg/dom/pull/1268,该集成已上游提交。
4.3. 与内容安全策略(Content Security Policy)的集成
4.3.1. require-trusted-types-for 指令
本文档定义了 require-trusted-types-for —— 一条新的内容安全策略指令。
require-trusted-types-for 指令为当前realm 内某些分组的全部 注入点 配置 Trusted Types 框架。它具体定义:当字符串值被传到某一分组的注入点时应采用何种行为(即是否启用类型强制)。
注: 目前仅规定了 § 2.1.1 DOM XSS 注入点 的强制。
directive-name = "require-trusted-types-for" directive-value = trusted-types-sink-group-keyword *( required-ascii-whitespace trusted-types-sink-group-keyword) trusted-types-sink-group-keyword = "'" trusted-types-sink-group "'" trusted-types-sink-group = "script"
4.3.1.1. require-trusted-types-for
预导航检查
给定 request(request),字符串 navigation type 和policy(policy),如果一次导航违反了 require-trusted-types-for 指令约束则返回
"Blocked",否则返回 "Allowed"。这就是 require-trusted-types-for 指令的预导航检查:
注: 此算法确保导航到 javascript: URL 时,执行的代码必须还要通过默认策略的 createScript 方法,以及 CSP 其他约束。
-
如果 request 的 url 的 scheme 不是
"javascript",则返回"Allowed"并终止。 -
令 urlString 为 URL serializer 处理 request 的 url 的结果。
-
令 encodedScriptSource 为去掉 urlString 前缀
"javascript:"后的结果。 -
令 convertedScriptSource 为调用通过默认策略处理值,参数为:
-
TrustedScript作为 expectedType -
encodedScriptSource 作为 input
-
"Location href"作为 sink
如该算法抛错或 convertedScriptSource 非
TrustedScript对象,则返回 "Blocked" 并终止。 -
-
将 urlString 设为用
"javascript:"前缀加上 convertedScriptSource 的字符串化结果。 -
令 newURL 为URL parser 处理 urlString 的结果。如为 failure,返回
"Blocked"并终止。 -
将 request 的 url 设为 newURL。
注: 没有其它 CSP 指令会在预导航检查处理
javascript:URL,其它指令在 inline check 阶段继续处理。 -
返回
"Allowed"。
4.3.2. trusted-types 指令
本文档定义了 trusted-types —— 一条新的 内容安全策略指令。trusted-types 指令用于控制 Trusted Types 策略的创建。
directive-name = "trusted-types" directive-value = serialized-tt-configuration serialized-tt-configuration = ( tt-expression *( required-ascii-whitespace tt-expression ) ) tt-expression = tt-policy-name / tt-keyword / tt-wildcard tt-wildcard = "*" tt-policy-name = 1*( ALPHA / DIGIT / "-" / "#" / "=" / "_" / "/" / "@" / "." / "%") tt-keyword = "'allow-duplicates'" / "'none'"
Content-Security-Policy: require-trusted-types-for 'script'; trusted-types one two
Content-Security-Policy: trusted-types; require-trusted-types-for 'script'
关键字 'none' 可用于显式表达上述含义:
关键字 'allow-duplicates' 允许重复策略名策略的创建。
如果策略名包含 default,则指的是 默认策略。
所有传递到 注入点
的字符串都会先通过该策略,而非直接被拒绝。
4.3.3. 注入点类型是否需要受信任类型?
如果注入点需要受信任类型,此算法返回true,否则返回false。
注入点类型是否需要受信任类型?算法,参数为全局对象(global)、字符串 (sinkGroup)和布尔值(includeReportOnlyPolicies),步骤如下:
-
对global的CSP 列表中的每个policy:
-
返回false。
4.3.4. 内容安全策略是否应阻止注入点类型不匹配违规?
如果注入点需要受信任类型,此算法返回"Blocked",否则返回"Allowed"。
内容安全策略是否应阻止注入点类型不匹配违规? 算法,参数为全局对象(global)、字符串(sink)、字符串(sinkGroup)和字符串(source),步骤如下:
-
令result为
"Allowed"。 -
令sample为source。
-
如果sink为
"Function",则:-
如果sample以
"function anonymous"开头,去除该内容。 -
否则如果sample以
"async function anonymous"开头,去除该内容。 -
否则如果sample以
"function* anonymous"开头,去除该内容。 -
否则如果sample以
"async function* anonymous"开头,去除该内容。
-
-
对global的CSP 列表中的每个policy:
-
如果policy的指令集不包含指令,其名称为
"require-trusted-types-for",则跳到下一个policy。 -
令directive为policy的directive set中指令,其名称为
"require-trusted-types-for" -
如果directive的值不包含匹配sinkGroup的trusted-types-sink-group,则跳到下一个policy。
-
令violation为执行创建全局、策略和指令的违规对象,参数为global、policy和
"require-trusted-types-for" -
将violation的资源设为
"trusted-types-sink"。 -
令trimmedSample为sample的前40字符子串。
-
将violation的示例设为用
"|"分隔的«sink, trimmedSample»。 -
对violation执行上报违规。
-
如果policy的执行状态为
"enforce",则result设为"Blocked"。
-
-
返回result。
4.3.5. 内容安全策略是否应阻止受信任类型策略的创建?
如果不应创建TrustedTypePolicy,此算法返回"Blocked",否则返回"Allowed"。
内容安全策略是否应阻止受信任类型策略的创建? 算法,参数为全局对象(global)、字符串 (policyName)和字符串列表 (createdPolicyNames),步骤如下:
-
令result为
"Allowed"。 -
对global的CSP 列表中的每个policy:
-
令createViolation为false。
-
令directive为policy的directive set中指令,其名称为
"trusted-types" -
如果directive的值只包含匹配值
'none'的tt-keyword,则createViolation设为true。注:与其它CSP指令一样,如果同时有其它关键字或策略名,则会忽略'none'。
-
如果createdPolicyNames包含policyName且directive的值不包含匹配
'allow-duplicates'的tt-keyword,则createViolation设为true。注:
trusted-types policyA policyB 'allow-duplicates'允许创建同名策略。 -
如果directive的值不包含值为policyName的tt-policy-name,也不包含tt-wildcard,则createViolation设为true。
注:
trusted-types *允许用任何唯一名字创建策略。若需多个同名策略,使用trusted-types * 'allow-duplicates'或不设置trusted-types。 -
如果createViolation为false,跳到下一个policy。
-
令violation为执行创建全局、策略和指令的违规对象,参数为global、policy和
"trusted-types" -
将violation的资源设为
"trusted-types-policy"。 -
将violation的示例设为policyName的前40字符子串。
-
对violation执行上报违规。
-
如果policy的执行状态为
"enforce",则result设为"Blocked"。
-
-
返回result。
5. 安全性注意事项
受信任类型并不旨在保护对注入点的访问不被蓄意恶意的执行环境绕过。默认假设应用由非恶意作者编写,目标是防止开发者失误导致的安全漏洞,并不防御主动规避策略限制的一方代码。下文列举了即使强制受信任类型,依然存在的风险向量。
5.1. 跨文档向量
当一个窗口中运行的代码已强制受信任类型时,无法动态创建绕过策略的新节点,
但仍有可能从未施加同等限制的其他窗口文档中导入或采用该节点。
本质上——如果恶意作者让受限文档与无限制文档“串通协作”,则可绕过 Trusted Types。
极端情况下,受限文档可直接把字符串封装成Blob并跳转过去。
CSP 传播规则(见Content Security Policy 3
§ 7.8 CSP继承机制防止绕过)可部分缓解此问题,因为新本地协议文档会继承同等限制。
比如,可以确保对Blob注入的内容不会执行脚本。要彻底防范该问题,还可结合Origin
Policy等机制,确保全域强制统一安全准则。
5.2. 已弃用特性
部分长久弃用且极少用的平台特性不受 Trusted Types 限制,恶意作者可能借此绕开约束:
5.3. 脚本组件(gadgets)
虽然 Trusted Types 机制会应用到许多字符串创建 DOM 树的操作,但它不应被用作全局保护文档内任意 DOM 树创建的机制。特别是在存在脚本组件(script gadgets)时,应用会响应通常安全的DOM元素或属性内容。直接用DOM API也可触发此类gadget,无须走受信任类型。但要触发 DOM XSS,gadget 仍需通过策略生成受信任值。作者应确保传给策略的数据确实可信,特别是策略本身未做约束或校验时。
5.4. 策略设计最佳实践
受信任类型将可通过注入点引入漏洞的代码范围限定为策略实现。 这种设计下,若策略本身不安全,依然可能让注入点暴露于不可信数据。 开发者需特别注意,仅使用对所有输入都安全的策略,或严格控制调用不安全策略,只能用非攻击者控制的输入。
策略是自定义 JS 代码,可写得严重依赖全局状态。不建议如此。策略应当尽量自包含。所有可影响策略安全决策的对象实际上都“变成”该策略,务必要一并保护和审查。
6. 隐私注意事项
本规范可能部分观测并修改应用中脚本行为,例如让某些注入点操作失败,或借助默认策略监控和变更注入点效果。 但事实上,更早的脚本原本就可通过覆盖属性描述符实现同样能力。
应用可主动上报受信任类型限制违规,违规报告会包含传给注入点的前40个字符负载(包括注入点名称)。该特性重用了内容安全策略的违规上报机制。
7. 实现相关注意事项
7.1. 厂商扩展与插件
受信任类型的限制不应干扰用户代理特性如插件、扩展、书签工具的正常运行。这些特性普遍体现了用户优先于页面作者的理念,见 [html-design-principles]。具体来说,扩展应能将字符串直接传递给注入点,不应触发默认策略执行、违规生成或值被拒绝。