1. 引言
本节不是规范性的。
随着 Web 平台不断扩展以支持更多有用和强大的应用程序,确保这些应用程序的功能仅在满足最低安全级别的上下文中启用变得越来越重要。作为 TAG 在 [SECURING-WEB] 中建议的延伸,本文档描述了 Web 上功能滥用的威胁模型(参见 § 4.1 威胁模型),并概述了应纳入新功能规范文档的规范性要求(参见 § 7 实现考量)。
此处讨论的最明显的要求是,能够访问敏感或私密数据的应用程序代码必须通过保证数据完整性的、经过身份验证的通道进行机密传输。安全地交付代码不能确保应用程序将始终满足用户的安全和隐私要求,但这是一个必要的前提条件。
不那么明显的是,通过经过身份验证和保密的通道交付的应用程序代码本身并不足以限制非安全上下文使用强大的功能。正如 § 4.2 祖先风险 所解释的,协作的框架可能被滥用以绕过对功能的其他可靠限制。下面定义的算法确保这些绕过是困难且用户可见的。
以下示例总结了随后的规范性文本:
1.1. 顶级文档
1.2. 框架文档
如果框架文档来自潜在可信的源,并且它们被嵌入到一个安全上下文中,那么它们可以是安全上下文。也就是说:
https://example.com/
在一个框架中打开
https://sub.example.com/
,那么两者都是安全上下文,因为它们都是通过经过身份验证和加密的通道交付的。
如果 https://example.com/
以某种方式能够框架
http://non-secure.example.com/
(也许用户覆盖了混合内容检查?),顶级框架将保持安全,但被框架的内容不是一个安全上下文。
另一方面,如果 https://example.com/
被框架在 http://non-secure.example.com/
内部,那么它不是一个安全上下文,因为它的祖先不是通过经过身份验证和加密的通道交付的。
1.3. Web Workers
专用 Workers 在性质上类似于框架文档。当它们从潜在可信的源交付时,它们是安全上下文,但前提是其所有者本身就是一个安全上下文:
如果在顶级浏览上下文中的
http://non-secure.example.com/
框架了 https://example.com/
,后者运行
https://example.com/worker.js
,那么被框架的文档和 worker 都不是安全上下文。
1.4. 共享 Workers
多个上下文可以附加到一个共享 Worker。如果一个安全上下文创建了一个共享 Worker,那么它就是一个安全上下文,并且只能由其他安全上下文附加。如果一个非安全上下文创建了一个共享 Worker,那么它不是一个安全上下文,并且只能由其他非安全上下文附加。
如果在顶级浏览上下文中的 https://example.com/
运行
https://example.com/worker.js
作为共享 Worker,那么文档和 worker 都被认为是安全上下文。
在另一个顶级浏览上下文(例如,在新窗口中)的
https://example.com/
是一个安全上下文,所以它可以访问安全的共享 worker:
同样,如果嵌套在 http://non-secure.example.com/
中的 https://example.com/
运行
https://example.com/worker.js
作为共享 Worker,那么文档和 worker 都被认为是非安全的。
1.5. 服务 Workers
服务 Workers 始终是安全上下文。只有安全上下文可以注册它们,并且它们只能拥有作为安全上下文的客户端。
如果在顶级浏览上下文中的 https://example.com/
注册了
https://example.com/service.js
,那么文档和服务 Worker 都被认为是安全上下文。
2. 框架
本节是非规范性的。
2.1. 与 WebIDL 的集成
一个新的 [SecureContext
]
属性可用于操作符,
它确保这些操作符只会被暴露到安全上下文中。
以下示例应该会有所帮助:
interface ExampleFeature { // 此调用将在所有上下文中成功。Promise <double >calculateNotSoSecretResult (); // 此操作不会暴露给非安全上下文。 [SecureContext ]Promise <double >calculateSecretResult (); // 此处同样适用:该操作不会暴露给非安全上下文。 [SecureContext ]boolean getSecretBoolean (); }; [SecureContext ]interface SecureFeature { // 此接口不会暴露给非安全上下文。Promise <any >doAmazingThing (); };
鼓励规范作者在定义新功能时使用此属性。
2.2. 与 HTML 的集成
2.2.1. 共享 Workers
SharedWorker
构造函数将在安全上下文尝试附加到一个非安全上下文的 Worker 时,以及非安全上下文尝试附加到一个安全上下文的 Worker 时,抛出一个“SecurityError
”
DOMException
异常。
2.2.2. 特性检测
应用程序可以通过检查定义在 WindowOrWorkerGlobalScope
上的 isSecureContext
布尔值来确定它是否在安全上下文中执行。
2.2.3. 安全和非安全上下文
3. 算法
3.1. origin 是否可能值得信赖?
一个潜在可信的源是指用户代理通常可以信任其安全地传输数据的源。
该算法将某些主机、协议和源视为潜在可信的,即使它们可能没有以传统意义上的方式进行身份验证和加密。特别是,用户代理应该将 file
URL
视为潜在可信的。原则上,用户代理可以将本地文件视为不可信的,但是,根据用户代理在运行时可用的信息,资源似乎已从磁盘安全地传输到用户代理。此外,将此类资源视为潜在可信的,对于在向公众部署应用程序之前构建应用程序的开发人员来说很方便。
然而,这种对开发人员的友好性并非没有风险。优先考虑安全性而非此类便利性的用户代理可以选择更严格地分配信任,以排除 file
。
另一方面,用户代理可以选择将此信任扩展到其他特定于供应商的 URL 方案,例如 app:
或 chrome-extension:
,它可以先验地确定这些方案是可信的(详见 § 7.1 打包应用程序)。
给定一个源
(origin),以下算法会酌情返回“Potentially Trustworthy
”或“Not Trustworthy
”。
-
如果 origin 是一个不透明源,则返回“
Not Trustworthy
”。 -
断言:origin 是一个元组源。
-
如果 origin 的协议是“
https
”或“wss
”, 则返回“Potentially Trustworthy
”。 -
如果 origin 的主机匹配 CIDR 表示法
127.0.0.0/8
或::1/128
[RFC4632] 之一, 则返回“Potentially Trustworthy
”。 -
如果用户代理符合 [let-localhost-be-localhost] 中的名称解析规则,并且以下之一为真:
则返回“
Potentially Trustworthy
”。注意:有关此处要求的详细信息,请参阅 § 5.2 localhost。
-
如果 origin 的协议是“
file
”,则返回 “Potentially Trustworthy
”。 -
如果 origin 的协议组件是用户代理认为已通过身份验证的组件,则返回“
Potentially Trustworthy
”。注意:有关此处的详细信息,请参阅 § 7.1 打包应用程序。
-
如果 origin 已被配置为可信源,则返回 “
Potentially Trustworthy
”。注意:有关此处的详细信息,请参阅 § 7.2 开发环境。
-
返回“
Not Trustworthy
”。
注意:origin 的域和端口都不会影响它是否被视为安全上下文。
3.2. url 是否可能值得信赖?
一个潜在可信的 URL
是指要么从其创建者继承上下文(about:blank
、about:srcdoc
、data
),要么其源是一个潜在可信的源。
给定一个URL
记录
(url),以下算法会酌情返回“Potentially Trustworthy
”或“Not Trustworthy
”:
-
如果 url 是“
about:blank
”或“about:srcdoc
”,则返回 “Potentially Trustworthy
”。 -
如果 url 的协议是“
data
”,则返回 “Potentially Trustworthy
”。 -
返回在 url 的源上执行 § 3.1 origin 是否可能值得信赖? 的结果。
注意:
blob:
URL 的源是创建它们的上下文的源。因此,在可信源中创建的 blob 本身也将是潜在可信的。
4. 威胁模型和风险
本节是非规范性的。
4.1. 威胁模型
在存在网络攻击者的情况下,向未经身份验证的源授予权限等同于向任何源授予权限。互联网的现状是,我们必须确实假设存在网络攻击者。通常,网络攻击者分为两类:被动攻击者和主动攻击者。
4.1.1. 被动网络攻击者
“被动网络攻击者”是指能够观察流量但缺乏能力或选择不在本规范所关注的层面上修改流量的一方。
以这种方式对网络进行监视“在未经通信各方同意的情况下颠覆了他们的意图”,并且“在允许其他行为者进行监视的情况下,无论某些人可能认为他们多么仁慈,都无法防御最邪恶的行为者。” [RFC7258] 因此,本文档中定义的算法需要提供应用层数据隐私的机制,而不仅仅是完整性。
4.1.2. 主动网络攻击者
“主动网络攻击者”具备“被动网络攻击者”的所有能力,并且还能够修改、阻止或重放任何通过网络的数据。这些能力可供各种能力的潜在对手使用,从提供或仅参与公共无线网络的受感染设备,到互联网服务提供商在为牟取经济利益而操纵流量时无意中引入安全和隐私漏洞([VERIZON] 和 [COMCAST] 是最近的例子),再到有直接意图损害安全或隐私并能够针对个人用户、组织甚至整个人群的各方。
4.2. 祖先风险
安全上下文算法会遍历特定上下文的所有祖先,以确定该上下文本身是否安全。为什么我们不认为一个在
iframe
中安全交付的文档本身就是安全的呢?
简短的回答是,这种模型会助长滥用。Chrome 对 [WEBCRYPTOAPI] 的实现是早期将 API 锁定到安全上下文的实验,它没有遍历上下文的祖先。当时的假设是,将 API
锁定到本身安全交付的资源就足以确保安全使用。然而,结果是像 Netflix 这样的实体构建了基于
iframe
和 postMessage()
的垫片,将 API 暴露给非安全上下文。这种限制只不过是一个减速带,减缓了对 API 的非安全访问,但在阻止此类访问方面完全无效。
虽然本文档中的算法并未将非安全上下文与安全上下文完全隔离(如 § 5.1 不完全隔离 中所讨论的),但祖先检查为这些上下文应提供的身份验证、机密性和完整性保证提供了相当强大的保护。
4.3. 与非安全上下文相关的风险
某些对用户安全或隐私有明显影响的 Web 平台功能应仅在安全上下文中可用,以防御上述威胁。在非安全上下文中可用的功能有将这些能力暴露给网络攻击者的风险:
- 读取和修改敏感数据(个人身份信息、凭据、支付工具等)的能力。[CREDENTIAL-MANAGEMENT-1] 是一个处理敏感数据的 API 示例。
- 读取和修改用户设备上传感器输入的能力(摄像头、麦克风和 GPS 尤其值得注意,但也肯定包括像加速度计这样不那么明显危险的传感器)。[GEOLOCATION-API] 和 [MEDIACAPTURE-STREAMS] 是使用传感器输入的历史功能示例。
- 访问用户有权访问的其他设备信息的能力。[DISCOVERY-API] 和 [WEB-BLUETOOTH] 是很好的例子。
- 使用临时或持久标识符跟踪用户的能力,包括在一段时间后重置自身的标识符(例如
window.sessionStorage
)、用户可以手动重置的标识符(例如 [ENCRYPTED-MEDIA]、Cookies [RFC6265] 和 [IndexedDB]),以及识别用户不易重置的硬件特征。 - 为某个源引入跨浏览会话持续存在的状态的能力。[SERVICE-WORKERS] 是一个很好的例子。
- 以某种方式操纵用户代理的本机 UI,从而移除、模糊或操纵与用户对其上下文理解相关的细节的能力。[FULLSCREEN] 是一个很好的例子。
- 引入需要用户许可的某些功能的能力。
此列表并非详尽无遗,但应能让您了解在编写或实现规范时应考虑的风险类型。
注意:虽然将功能本身限制在安全上下文中至关重要,但我们不应忘记,承载此类信息的设施(例如新的网络访问机制,或其他可访问网络数据的通用功能)同样敏感。
5. 安全考量
5.1. 不完全隔离
本文档中的安全上下文定义并未完全隔离同一来源的“安全”视图和“非安全”视图。通过日益深奥的机制,例如
localStorage
/sessionStorage
的内容、storage
事件、BroadcastChannel
等,数据泄露仍然是可能的。
5.2. localhost
[RFC6761] 的第 6.3
节规定了 localhost.
和 .localhost.
内的名称解析是特殊的,并建议本地解析器应该/可以特殊处理它们。无论好坏,解析器通常会忽略这些建议,并在许多情况下将 localhost
发送到网络进行解析。
鉴于这种不确定性,用户代理可以将 localhost 名称视为具有潜在可信来源,当且仅当它们也遵守 [let-localhost-be-localhost] 中阐明的 localhost 名称解析规则(其核心是确保
localhost
永远不会解析为非环回地址)。
6. 隐私考量
本文档中的安全上下文定义本身没有任何隐私影响。然而,它确实使其他具有有趣隐私影响的功能能够将自己锁定在可以确保完整性、真实性和机密性得到特定保证的上下文中。
从隐私的角度来看,鼓励规范作者考虑为其定义的功能要求安全上下文。
7. 实现考量
7.1. 打包应用程序
支持打包应用程序的用户代理可以将某些 URL 方案视为“安全的”,只要其内容经过用户代理的身份验证。例如,FirefoxOS 应用程序资源由一个 URL 引用,其方案组件是
app:
。同样,Chrome 的扩展和应用程序位于 chrome-extension:
方案上。这些可以合理地被认为是受信任的来源。
7.2. 开发环境
为了支持在非环回主机上运行预发布服务器的开发人员,用户代理可以允许用户将特定的来源集配置为可信的,即使 § 3.1 来源是否可能值得信赖? 通常会返回“Not Trustworthy
”。
7.3. 限制新特性
本节是非规范性的。
在为新特性编写规范时,我们建议作者和编辑通过检查安全上下文来保护敏感的 API。例如,类似下面的方法可能是一个好方法:
作者也可以通过使用 [SecureContext
]
属性来保护敏感 API,从而确保它们只暴露给安全上下文。
[SecureContext ]interface SensitiveFeature {Promise <double >getTheSecretDouble (); }; // 或者:interface AnotherSensitiveFeature { [SecureContext ]void doThatPowerfulThing (); };
7.4. 限制旧有特性
本节是非规范性的。
上面的列表清楚地包括了一些当前在非安全通道上可用的现有功能。我们建议尽快[W3C-PROCESS]修改这些旧有功能,以开始要求安全上下文。
-
如果某个此类功能已被广泛实现,但尚未被广泛使用,我们建议通过在现有实现中添加如 § 7.3 限制新特性 中所述的检查,并相应地修改规范,来迅速将其限制在安全上下文中。
-
如果某个此类功能已被广泛使用,我们建议弃用现有功能;应修改规范,以指出它不符合本文档中概述的限制,并应制定一个计划,既提供该功能的合规版本,又将现有用户迁移到该新版本中。
7.4.1. 示例:地理定位
[GEOLOCATION-API] 是此类功能的一个很好的具体例子;它在大量非安全网站上被广泛实现和使用。一个合理的前进路径可能如下所示:
-
修改规范,在执行
getCurrentPosition()
和watchPosition()
的算法之前,包含对安全上下文的检查。如果当前设置对象不是一个安全上下文, 则应中止算法,并调用
errorCallback
,其code
为PERMISSION_DENIED
。 -
用户代理应宣布明确的意图,在特定日期禁用非安全上下文的 API,并相应地警告开发人员(例如,通过控制台消息)。
-
在标志日到来之前,用户代理应宣布一个弃用时间表,以确保网站作者认识到需要在其代码完全停止工作之前进行修改,并在此期间保护用户。这样的计划可能包括以下任何或所有内容:
-
禁止对非安全来源授予持久权限
-
降低非安全来源 API 的精度(例如,始终返回城市级别的数据而不是高精度数据)
-
修改 UI 以告知用户和网站作者风险
-
-
8. 致谢
本文档主要基于 Chrome 安全团队在 [POWERFUL-NEW-FEATURES] 上的工作。Chris Palmer、Ryan Sleevi 和 David Dorwin 尤其积极参与。Anne van Kesteren、Jonathan Watt、Boris Zbarsky 和 Henri Sivonen 也提供了非常有帮助的反馈。