1. 引言
本节不是规范性的。
尽管 [RFC1918] 已经指定了“私有”和“公共” 互联网地址之间的区别二十多年,但用户代理在将二者彼此隔离方面并没有取得太多进展。公共互联网上的网站可以向本地设备和服务器发出 请求,这会导致许多恶意 行为,包括对用户路由器的攻击,例如 [DRIVE-BY-PHARMING], [SOHO-PHARMING] 和 [CSRF-EXPLOIT-KIT] 中记录的那些攻击。
本地网络访问旨在防止这些对本地网络上不安全 设备的不期望请求。这通过弃用公共网站对 本地 IP 地址的直接访问来实现,并改为要求用户 授予发起网站连接到其本地 网络的权限。
注: 此提案建立在 Chrome 先前 暂停的 [PRIVATE-NETWORK-ACCESS] 工作之上,但不同之处在于它通过权限 来门控访问, 而不是通过预检请求。
1.1. 目标
总体目标是防止用户代理无意中启用 对运行在用户本地内联网中的设备,或直接运行在 用户机器上的服务的攻击。例如,我们希望缓解对以下对象的攻击:
-
用户的路由器,如 [SOHO-PHARMING] 中概述。注意,现状下的 CORS 保护无法防止这里讨论的这类攻击,因为它们 只依赖 CORS 白名单方法和 CORS 白名单请求标头。不会触发 CORS 预检,而攻击者并不 关心读取响应,因为请求本身就是 CSRF 攻击。
-
在用户环回地址上运行 Web 接口的软件。不管好坏, 这正成为各种 应用程序的常见部署机制,并且经常假定存在实际上并不存在的保护(参见 [AVASTIUM] 和 [TREND-MICRO] 中的近期示例)。
当用户既预期又明确允许发生本地网络访问请求时, 应当有一条明晰的路径来允许这些请求。 例如,登录到 plex.tv 的用户可能希望允许 该站点连接到其本地媒体服务器,以便通过本地网络直接加载媒体内容, 而不是通过远程服务器路由。更多示例见下文 § 1.3 示例。
1.2. 非目标
此规范不试图让在本地 网络设备上使用 HTTPS 连接变得更容易。虽然这会是一个有用的目标,但解决此问题超出 本规范的范围
1.3. 示例
1.3.1. 用户授予权限
Alice 访问 Acme Printing Company 的网站以帮助诊断问题。 Acme Printing Company 的网站告诉 Alice,它可以连接到打印机 以查看打印机的诊断输出。Alice 的浏览器询问 Alice 是否 允许 https://support.acmeprintingcompany.com 连接到她 网络上的本地设备。Alice 授予 https://support.acmeprintingcompany.com 连接到她 网络上的本地设备的权限,并且 https://support.acmeprintingcompany.com 连接到她本地 打印机的诊断输出,并告诉 Alice 打印机上的一个部件发生故障, 需要更换。
1.3.2. 用户拒绝权限
1.3.3. 新设备配置
1.3.4. 基于应用的登录
2. 框架
2.1. IP 地址空间
如下定义 IPAddressSpace:
enum {IPAddressSpace ,"public" ,"local" };"loopback"
每个 IP 地址都属于一个 IP 地址 空间,它可以是三个不同值之一:
-
环回:包括环回地址, 这些地址仅可在本地主机上访问。换句话说,其 目标因设备而异的地址。
-
本地:包含仅在当前网络中 有意义的地址。换句话说,其目标 根据网络位置而异的地址。
-
公共:包含所有其他 地址。换句话说,其目标在 IP 网络上对全球所有设备 都相同的地址。
为方便起见,我们还定义以下术语:
一个 IP 地址空间 lhs 比另一个 IP 地址空间 rhs 更不公共,如果满足以下任一条件:
要确定 IP 地址空间,给定一个 IP 地址 address,运行以下步骤:
-
如果 address 属于
::ffff:0:0/96"IPv4-mapped Address" 地址块,则将 address 替换为其嵌入的 IPv4 地址。 -
对于 非公共 IP 地址块 表中的每个 row:
-
如果 address 属于 row 的地址块,则返回 row 的 地址空间。
-
-
返回公共。
| 地址块 | 名称 | 引用 | 地址空间 |
|---|---|---|---|
127.0.0.0/8
| IPv4 环回 | [RFC1122] | 环回 |
10.0.0.0/8
| 私有使用 | [RFC1918] | 本地 |
100.64.0.0/10
| 运营商级 NAT | [RFC6598] | 本地 |
172.16.0.0/12
| 私有使用 | [RFC1918] | 本地 |
192.168.0.0/16
| 私有使用 | [RFC1918] | 本地 |
198.18.0.0/15
| 基准测试 | [RFC2544] | 环回 |
169.254.0.0/16
| 链路本地 | [RFC3927] | 本地 |
::1/128
| IPv6 环回 | [RFC4291] | 环回 |
fc00::/7
| 唯一本地 | [RFC4193] | 本地 |
fe80::/10
| 链路本地单播 | [RFC4291] | 本地 |
fec0::/10
| 站点本地单播 | [RFC3513] | 本地 |
0.0.0.0/32
| IPv4 空 IP 地址 | [RFC1884] | 环回 |
0.0.0.0/8
| IPv4 空 IP 地址 | [RFC1884] | 本地 |
::/128
| IPv6 未指定地址 | [RFC1884] | 环回 |
2001:db8::/32
| IPv6 文档地址 | [RFC3849] | 本地 |
3fff::/20
| IPv6 文档地址 | [RFC9637] | 本地 |
::ffff:0:0/96
| IPv4 映射 | [RFC4291] | 见映射的 IPv4 地址 |
用户代理可以允许通过管理员或用户配置覆盖某些 IP 地址块的地址空间。 这可能有助于保护例如 IPv6 内联网,在这些内联网中,按照上述算法大多数 IP 地址都被视为 公共, 而通过配置用户代理将该内联网视为本地。
注: 链路本地 IP 地址,例如
169.254.0.0/16 被视为
本地,
因为这类地址可以标识网络链路上所有设备的同一
目标。此规范的早期版本曾改为将它们视为环回。
注: 每个 IP 地址空间 的内容曾在某个时期
根据 IANA Special-Purpose Address Registries
([IPV4-REGISTRY] 和 [IPV6-REGISTRY])以及其中定义的
Globally Reachable 位
来确定。事实证明,对于我们的用途来说,这是一个不准确的信号,
如 wicg/private-network-access
issue #50 中所述。
注: [PRIVATE-NETWORK-ACCESS] 使用了 public、private 和 local 这些地址空间。此规范分别将这些地址空间重命名为 public、local 和 loopback。
注: [FETCH] 计划指定,对空 IP 地址的请求将被
视为网络错误。我们将 IPv4 空 IP 地址空间和
IPv6 未指定地址都映射为环回,因为某些系统仍然可以
将它们路由回本地主机机器(并且 0.0.0.0/8 可以指
“此网络上的指定主机”,因此根据 本地
进行映射)
见 [RFC5735]。一旦 Fetch 的更改完成并被采用,
我们将
不再需要在此规范中处理它们。
2.2. 本地网络请求
一个 请求(request)是一个 本地网络请求,
如果 request 的当前 url 的 host
映射到一个 IP 地址,
其 IP 地址空间
比 request 的 policy container 的
IP 地址空间更不公共。
将 IP 地址分类为两个宽泛地址空间是一种 不完善且理论上不严谨的方法。它是一种代理,用于确定 两个网络端点是否应当被允许自由通信, 换句话说,端点 A 是否可以在不通过端点 C 上的用户代理中转的情况下 从端点 B 到达。
这种方法有一些缺陷:
-
漏报:连接到两个不同 本地网络(例如家庭网络和 VPN)的客户端,可能 允许从 VPN 提供服务的网站访问家庭网络上的设备。 另请参见下面的问题。
即便如此,此规范仍旨在为一个广泛影响大多数 Web 用户的安全 问题提供一种务实的解决方案,这些用户的网络配置 并不那么复杂。
源自环回地址的请求不应被视为 本地网络 请求,也不应受到本地网络访问 检查的约束,因为在用户设备上运行的任何软件已经处于用户网络中最 特权的观察位置。
本地网络
请求的定义可以扩展为覆盖
所有跨源请求,其中当前 url 的 host
映射到一个 IP 地址,其IP 地址空间不是公共。这将防止本地网络上的
恶意服务器攻击其他服务器,包括 localhost 上的服务器。见
wicg/private-network-access issue
#39。
注: 目前,Chromium 只对从 公共到 本地或环回的请求实现本地网络 访问限制,并且不对跨源 本地 请求强制执行该权限。此限制可以作为 未来实现中的增量改进发布。
注: 因为本地名称和地址在 网络边界之外没有意义, 实现者可能希望对跨源本地情形使用不同的权限提示,而不是对 公共到本地 的情形使用同一提示。此外,实现者 可能希望将这些权限授予限定到特定网络或仅限于 当前浏览会话。
注: 某些本地网络请求比其他请求 更难保障安全。 更多详情见 § 4.4 推出困难。
2.3. 本地网络请求权限提示
引入本地网络访问权限提示,以允许用户 批准来自公共网站到本地网络服务器的本地 网络请求。
当检测到本地 网络请求时,会向用户显示提示, 请求访问本地网络的权限。如果用户决定授予 权限,则 fetch 继续。否则,它失败。
权限的确切范围由实现定义。该权限可以 粗粒度到允许特定源向本地网络上的任何 端点发送本地网络请求,也可以更细粒度, 只允许特定源与本地 网络上的特定端点通信。用户代理可以持久化此决定以减少权限疲劳。
2.4. 安全上下文限制
发出本地网络请求的能力是一项强大特性, 并且必须只允许来自安全上下文。
为了将来能够对所有跨源本地请求应用 LNA
检查(见上面的问题),Chromium 计划
将那些目前很可能无法获得公开信任 HTTPS
证书的本地服务器从此要求中豁免(例如 .local 上的服务器和私有 IP
字面量)。更多讨论见 § 4.4 推出困难,另请见
wicg/private-network-access issue
#96。
2.5. 混合内容
许多本地网络服务器不运行 HTTPS,因为事实证明 将本地网络服务器从 HTTP 迁移出去很困难 (有时甚至不可能)。这是有问题的,因为安全上下文限制结合混合 内容检查,即使用户愿意 授权请求发生,也会阻塞许多本地网络请求。
解决此问题的一种方案是在已知请求是本地网络请求的情况下 绕过混合内容检查。在以下几种情况下可以知道这一点:
-
当请求目标的主机名是在非公共 IP 地址块" 表中被标识为本地的 IP 字面量时 (例如 [RFC1918] IP 字面量)
-
当请求的主机名是 .local 域(RFC 6762)时
可能存在一些情况,上述两种情况都不成立,
但站点仍希望将请求标识为本地网络请求。这
可以通过向 fetch() 选项包添加一个新参数来缓解:
fetch( "http://router.local/ping" , { targetAddressSpace: "local" , });
这会指示浏览器允许 fetch 绕过混合内容检查,
即使方案是不安全的,并可能获得到
目标服务器的连接。新的 fetch() API 是向后兼容的。
注意,此特性不能被滥用来一般性地绕过混合内容。如果 解析出的远程 IP 地址不属于 指定为 targetAddressSpace 选项值的 IP 地址空间,则请求将失败。 如果它属于该地址空间,则可以检查权限以允许或失败该 请求。
Chromium 目前
支持一个非标准 CSP 指令 treat-as-public-address
(见 private-network-access#csp)。
如果实现了 wicg/private-network-access issue
#39,此指令将变得不再必要。
2.6. 权限
此文档定义以下默认强大特性,它们是 策略控制特性,并具有 默认允许列表 'self':
注: 以前,这被指定为单个默认强大特性,覆盖
本地和环回两种情况,"local-network-access"。
Chromium 仍支持它作为新的细粒度权限名称的别名,并且
用作策略控制特性名称。
3. 集成
本节是非规范性的。
此文档提出对其他规范进行若干修改,以 实现上面概述的保护。这里列出这些集成 是为了清晰起见,但外部文档才是规范性引用。
3.1. 与 Fetch 集成
此文档提出对 [FETCH] 进行一些更改,具有如下含义: 仅当本地网络 请求的 client 是一个安全上下文 并且用户授予了权限时才允许这些请求。如果请求本来会因 混合内容而被阻塞,那么只要网站声明其 访问本地网络的意图,并且用户授予权限,就可以允许该请求。
注: 这包括导航。它们确实可以被 用来触发 CSRF 攻击,尽管没有子资源请求那么隐蔽。
Chromium 目前只将 LNA 限制应用于 iframe 导航。 值得考虑将其扩展到包括主框架导航(尤其是 可被其 opener 控制的弹出窗口)。
注: [FETCH] 尚未将 DNS 解析的 细节集成到 Fetch 算法中,不过它确实 定义了一个获得连接算法, 这对本规范已经足够。本地网络访问检查应用于 新获得的连接。考虑到 Happy Eyeballs 等复杂性 ([RFC6555], [RFC8305]),这些检查 对于具有多个跨越 IP 地址空间边界的 IP 地址的主机可能会非确定性地通过或失败。
3.1.1. 获取
注: [FETCH] 中的连接管理有意保持有些 模糊,因此下面的一些内容通过给实现者的注释来解释。本节说明 实现者在获得连接之后、继续使用该连接执行 fetch 之前 执行本地网络访问检查。
为了解决 wicg/local-network-access issue #103, 我们将需要改为集成到获得连接的步骤 4.6 中,以便在解析 origin 之后但在实际创建连接之前执行检查。
按如下方式更新 [FETCH]:
-
Connection 对象被赋予一个新的 IP 地址属性,其值为 null 或一个IP 地址,初始为 null。
-
向创建连接算法添加一个新步骤,紧接在 建立新连接之后(步骤 2 和 3 之间)。
-
Request 对象被赋予一个新的 目标 IP 地址空间属性,初始为 null。
-
定义一个新的 本地网络访问检查算法。 给定一个请求 request 和一个IP 地址 address:
注: 此算法接受一个IP 地址,以便它可以从 HTTP-network fetch(在那里我们有一个connection)或 HTTP-network-or-cache fetch(在那里我们有一个存储的 response,且带有保存的 IP 地址)中调用。 这会有意每次重新计算 IP 地址空间,因为映射 可以由用户代理动态更新。
-
令 addressSpace 为在 address 上运行确定 IP 地址空间算法的结果。
-
如果 request 的origin 是一个潜在可信 origin,并且 request 的current URL 的origin 与 request 的origin同源,则返回 null。
-
如果 request 的policy container 为 null,则返回 null。
注: 如果 request 的policy container 为 null,则 LNA 检查不适用于 request。fetch 算法的用户 必须小心,要么将 request 的client 设置为一个 environment settings object,且具有非 null 的 policy container,并让 fetch 相应地初始化 request 的 policy container,要么 直接将 request 的policy container设置为非 null 值。
-
如果 request 的目标 IP 地址空间不是 null:
-
断言:request 的目标 IP 地址空间不是 公共。
-
如果 addressSpace 不等于 则 request 的目标 IP 地址空间,则 返回 一个网络错误。
-
返回 null。
-
-
如果 addressSpace 比 request 的 policy container 的IP 地址空间更不公共:
-
令 error 为一个网络错误。
-
将 error 的IP 地址属性设置为 address。
-
令 permissionName 为 "local-network",如果 addressSpace 是本地;或者为 "loopback-network",如果 addressSpace 是环回。
-
令 settingsObject 为 request 的client。
-
令 global 为 settingsObject 的global object。
-
令 document 为 global 的关联 Document。
-
如果 document 为 null,则返回 error。
注: 此步骤会导致来自 Service Workers 的本地 网络请求失败,因为 Service Workers 并不总是拥有 关联的 Document。此规范的未来版本需要 定义如何处理 Workers,尤其是因为 Permissions Policy 尚未在 Workers 中受支持。见 w3c/webappsec-permissions-policy#207。
-
如果 document 不被允许使用 permissionName,则返回 error。
-
令 permissionState 为给定 permissionName 和 global 后 获取当前 权限状态的结果。
-
如果 permissionState 是denied,则返回 error。
-
如果 permissionState 是granted,则返回 null。
-
提示用户选择是否 为 global 授予 permissionName:
-
如果用户授予权限,则返回 null。
-
如果用户拒绝权限,则返回 error。
-
-
-
返回 null。
-
-
fetch 算法被修正为在设置 request 的 policy container 之后立即添加 2 个新步骤:
-
如果 request 的目标 IP 地址空间为 null:
-
如果 request 的URL 的host host 是一个IP 地址 并且在 host 上运行确定 IP 地址空间算法的结果 是本地,则将 request 的 目标 IP 地址空间设置为本地。
-
如果 request 的URL 的host 的public suffix 是
"local",则将 request 的目标 IP 地址空间设置为 本地。注: 如果请求的 URL 的 host 是 “localhost” 或 “127.0.0.1”(因为 [LET-LOCALHOST-BE-LOCALHOST]), 我们也可以将目标 IP 地址空间设置为 本地, 但我们不需要 对环回情况进行特殊处理,因为它已经被视为 潜在可信,不会触发混合内容检查。
注: 如果目标 IP 地址空间已经是非 null,我们不会在这里设置它, 以便优先使用由 fetch() API 设置的显式 targetAddressSpace。
-
-
-
HTTP-network fetch 算法被修正为在 检查新获得的 connection 不是 failure 之后立即添加 3 个新步骤:
-
HTTP-network-or-cache fetch 算法被 修正为在步骤 9 之后立即添加一个新步骤:
注: 本地网络请求必须从安全上下文 发出的要求意味着,任何不安全请求都会因混合内容而被阻塞,除非我们能 预先知道该请求可以被视为本地网络 请求。通过设置目标 IP 地址空间属性(见上面的步骤 6i 和 6ii), 我们只需要对 Mixed Content 做一个小改动——见 § 3.2 与 Mixed Content 集成。
3.1.2. Fetch API
Fetch API 也需要调整。
-
向
RequestInfo附加一个可选entry, 其key 为 targetAddressSpace,且value 为IPAddressSpace。partial dictionary RequestInit {IPAddressSpace ; };targetAddressSpace -
定义一个新的 targetAddressSpace,表示 上述request中的内容。
partial interface Request {readonly attribute IPAddressSpace ; };targetAddressSpace -
new Request(input, init)在将 this 的request 设置为 request 之前追加以下步骤:-
如果 init["
targetAddressSpace"] 存在,则 switch on init["targetAddressSpace"]:- public
- 不做任何事。
- local
- 将 request 的 targetAddressSpace 设置为本地。
-
3.2. 与 Mixed Content 集成
Should fetching request be blocked as mixed content? 被修正为 向其中一个 allowed 条件添加 以下条件:
-
request 的origin不是潜在可信 origin, 并且 request 的目标 IP 地址空间是本地。
"Upgrade request to an a priori authenticated URL as mixed content, if appropriate" 算法被修正为在步骤 1 中添加以下条件作为 升级的例外:
-
request 的目标 IP 地址空间是本地
3.3. 与 WebSockets 集成
WebSockets 连接应当受到相同的本地网络访问 权限要求的约束。WebSocket opening handshake 在步骤 11 中直接应用 fetch, 因此除了上面提出的 fetch 更改之外,不需要对 WebSocket 规范进行 修改。
Fetch API 和 WebSockets API 之间的一个小差异是
WebSockets 没有等同于 fetch 的 RequestInit 的东西,因此
没有地方放置 targetAddressSpace 选项以绕过 ws:// url 的混合内容
检查。
3.4. 与 WebTransport 集成
WebTransport 连接应当受到相同的本地网络访问 权限要求的约束。
不需要修改 WebTransport 规范。在 WebTransport 规范中,获得 WebTransport 连接 在步骤 6 中引用 Fetch 规范来获得连接,而该部分正由 § 3.1.1 获取修改
3.5. 与 HTML 集成
为支持 [FETCH] 中的检查, 用户代理必须记住发出网络请求的上下文的源 IP 地址空间。为此, [HTML] 规范按如下方式修补:
-
向 policy container struct 添加一个新的 IP 地址空间 属性。
-
它最初为 public。
-
-
向 clone a policy container 算法添加一个额外步骤:
-
向 create a policy container from a fetch response 算法添加一个额外步骤:
-
将 result 的IP 地址空间设为 在 response 的IP 地址上运行确定 IP 地址空间 算法的结果。
-
example.com 解析到一个公共地址(比如
123.123.123.123),那么导航到
https://example.com/document.html 时创建的 Document
将使其
policy container 的IP 地址
空间
属性设置为公共。
如果此 Document
随后嵌入一个 about:srcdoc iframe,那么子
frame 的 Document
将使其 policy container 的
IP 地址空间属性设置为
公共。
另一方面,如果 example.com 解析到一个本地地址
(比如 127.0.0.1),那么导航到
https://example.com/document.html 时创建的 Document
将使其
policy container 的IP 地址
空间
属性设置为本地。
TODO:还要更新 HTML § 7.1.4 Cross-origin embedder policies 中对 Private Network Access 的引用。
3.6. 与 Workers 集成
本节是非规范性的。
鉴于 WorkerGlobalScope
已经有一个
policy container 字段,该字段使用
create a policy container from a fetch
response 算法填充,上述与 Fetch 和 HTML 的集成
对 worker 上下文和对文档一样适用。
example.com 解析到一个公共地址(比如
123.123.123.123),那么通过从
https://example.com/worker.js 获取
脚本而创建的 WorkerGlobalScope
将使其
policy container 的
IP 地址空间属性设置为
公共。
此 worker 发起的任何 fetch request,如果获得连接 到 本地或 环回地址空间中的 IP 地址,那么它将是一个 本地网络 请求。
Chromium 的实现 目前根据 worker 的脚本源应用 LNA 权限于 service worker 发起的 fetch(因为当 service worker 正在 执行时,周围可能没有活动文档)。基于 worker 的分区存储 key 来进行这一点可能更好,并且如果 permissions policy 支持 service workers 也会很好。
Service Worker soft update 算法 不幸地在 fetching 更新脚本时, 将request client 设置为 "null"。 这会导致各种问题,并干扰上面列出的本地网络访问 检查算法。事实上,没有request client 可用于 在 fetch 期间复制 policy container。 见 wicg/private-network-access issue #83。
4. 实现考虑事项
4.1. File URL
尚不完全清楚 file URL 如何适配上面概述的公共/本地方案。 一方面,最好能防止人们通过在本地打开 恶意 HTML 文件来伤害自己;但另一方面,在本地运行的代码 在某种程度上超出了任何连贯的威胁模型。
目前,让我们倾向于将 file URL 视为本地,因为它们 看起来与环回地址上的任何东西一样都是本地系统的一部分。
4.2. 代理
在 Chromium 对此规范的当前实现中,代理 会影响它们代理的资源的地址空间。具体而言, 通过代理获取的资源被视为从代理本身的 IP 地址获取。
如果一个由公共地址上的 foo.example 提供服务的 Document 被 用户代理通过本地地址上的代理获取,那么该 Document 的policy container 的IP 地址空间被设置为本地。
该 Document 随后将被允许向浏览器可访问的其他本地 地址发出请求。
这可能允许网站通过观察其是否被允许向本地地址发出请求 来获知它曾通过代理访问,这是一种隐私信息 泄漏。虽然这要求正确猜测本地 网络上资源的 URL,但一次正确猜测就足够了。
预计这种情况相对少见,不足以需要更多缓解措施。 毕竟,在现状下,所有网站都可以不受任何限制地向所有 IP 地址 发出请求。
探索一种机制会很有趣,通过这种机制,代理可以告诉 浏览器“请仍将此资源视为 public/local”,从而传递 一些关于代理背后 IP 地址的信息。
4.3. HTTP 缓存
来自 HTTP 缓存的响应受本地网络访问 检查约束,如上文 § 3.1 与 Fetch 集成 中所指定。 下面是一些额外细节,说明这些检查在实践中如何工作 (带有一些示例),具体取决于从缓存加载哪种资源。
4.3.1. 主资源
从缓存的response 构造的document会记住 该response 最初加载自的 IP 地址。该 document 的 IP 地址空间会从该 IP 地址重新派生。
在常见情况下,这意味着该document 的policy container 的 IP 地址空间会原样恢复。然而,如果用户 代理的配置发生变化,派生出的 IP 地址空间可能 不同。
随后用户代理重启,并应用一个新配置,指定 1.2.3.4 should 改被分类为本地地址。
用户代理再次导航到 http://foo.example/,并从 HTTP 缓存加载主 资源。生成的document 的 policy container 的 IP 地址空间现在设置为 local。
4.3.2. 子资源
与主资源一样,从缓存响应构造的子资源 会记住响应最初加载自的 IP 地址。响应的 IP 地址空间会从该 IP 地址重新派生。
在常见情况下,这意味着响应的 IP 地址空间会 原样恢复。然而,如果用户代理的配置 发生变化,派生出的 IP 地址空间可能不同。
当子资源请求被 LNA 检查阻塞(即权限被 拒绝)时,不会缓存任何资源响应。如果之后重置 或授予权限,子资源请求将转到网络。
用户代理导航到 https://foo.example,它从 1.2.3.4
加载(其 IP 地址空间为 public)。文档触发一个
针对 http://bar.local/image.jpg 的子资源请求,当创建连接时
其 IP 地址为 10.0.1.1(其 IP 地址空间为
local)。这触发权限提示,向 https://foo.example 授予 Local Network Access
权限,然后加载该子资源并将其添加到
用户代理的缓存中。
用户代理重置 https://foo.example 的权限。
用户代理再次导航到 https://foo.example, 这又触发一个针对 http://bar.local/image.jpeg 的子资源请求。该资源位于 用户代理的缓存中,具有缓存的响应 IP 地址 10.0.1.1。这 再次触发权限提示,如果授予权限,将完成从用户代理缓存加载该 资源。
用户代理导航到 https://foo.example,它从 1.2.3.4
加载(其 IP 地址空间为 public)。文档触发一个
针对 http://bar.local/image.jpg 的子资源请求,当创建连接时
其 IP 地址为 10.0.1.1(其 IP 地址空间为
local)。这触发权限提示,拒绝 https://foo.example 的 Local Network Access
权限。子资源请求被阻塞,并且没有
资源被添加到用户代理的缓存。
用户代理重置 https://foo.example 的权限。
用户代理再次导航到 https://foo.example, 这又触发一个针对 http://bar.local/image.jpeg 的子资源请求。该资源不在用户代理缓存中,因此 会经过 HTTP network fetch 并触发权限提示。
有关安全影响的讨论,见 § 5.6 HTTP 缓存。
4.4. 推出困难
本地网络访问本质上弃用了对本地网络的直接访问, 转而采用更安全的由用户代理中介的替代方案。Web 弃用 很困难。Chromium 之前在发布 [PRIVATE-NETWORK-ACCESS](此 规范的前身)部分功能的过程中遇到了许多障碍。
特别是,对从本地 IP 地址空间中的
非安全上下文向 localhost 上服务发出的 fetch 发布限制
被证明尤其
困难,且收益较低。事实上,利用这类 fetch 要求
攻击者已经在私有网络中站稳脚跟,这
大幅提高了攻击难度。因此,Chromium 暂时豁免了
这些 fetch 的限制,选择专注于来自
公共 IP 地址空间的 fetch。有关安全影响的讨论见
§ 5.5 本地网络攻击者。
5. 安全和隐私考虑事项
5.1. 用户中介
此文档中的提案只确保用户同意来自 公共互联网的访问。此提案不允许设备 明确批准来自公共互联网的连接。
一种由设备必须明确批准来自公共互联网连接的替代模型 曾在 [PRIVATE-NETWORK-ACCESS] 中尝试过,但 遇到了 推出困难。
要求用户中介,无论目标端点是否选择加入该 连接,也有助于缓解隐私问题,例如 "Local Mess" 跟踪方法,其中本地 端点和远程网站串通以关联用户身份。
5.2. DNS 重绑定
这里描述的缓解措施基于用户代理在加载特定资源时 实际连接到的 IP 地址进行操作。必须 对每个新建连接执行此检查,因为 DNS 重绑定攻击否则 可能诱使用户代理泄露不应泄露的信息。
DNS 重绑定攻击也意味着本地网络访问检查必须适用于
所有 public 到 local 的请求(也就是说,我们不能将算法简化为
“任何到 local 端点的跨源请求”,因为这会带来这样的风险:
用户导航到 a.example,随后移动网络或 DNS 变化使
a.example 指向本地地址)。
5.3. 缓解范围
此文档中的提案仅缓解针对本地 Web 服务的攻击,不能完全解决它们。例如,路由器的基于 Web 的 管理界面必须自行设计和实现以防御 CSRF,不应依赖按本文档规定行为的 UA。 本文档指定的缓解措施在当前本地 Web 服务实现质量的现实下是必要的, 但厂商不应 认为自己可以免除责任,即使所有 UA 都实现此 缓解措施。
5.4. 跨网络混淆
大多数本地网络无法彼此通信,但它们都被 此规范视为属于本地 IP 地址空间。进一步来说, 本地地址只在使用它们的本地网络中有意义。 同一个 IP 地址在两个不同网络中可能指代完全不同的设备。 用户授予 a.example 发出本地 网络请求的权限后,可能移动到不同网络,然后 a.example 仍将能够发出本地网络请求。
这为跨网络攻击打开了大门:
-
用户连接到两个不同的本地网络:家庭 Wi-Fi 网络和 企业 VPN。他们的智能冰箱被入侵。他们打开智能 冰箱的 Web 界面,随后该界面对可通过 VPN 访问的企业 网站执行 CSRF 攻击。
-
用户连接到恶意网吧 Wi-Fi,该 Wi-Fi 要求用户 保持强制门户页面打开。用户合上笔记本电脑,回家后 再次打开笔记本电脑。强制门户页面(要么仍然打开,要么在用户代理恢复其先前状态时 从缓存重新加载)执行 CSRF
-
攻击用户的家庭设备。
-
用户连接到恶意网吧 Wi-Fi,其强制门户 网站从 http://router.example/popular-library.js 缓存了一个恶意脚本(网吧网络管理员 运行恶意 DNS 服务器),并设置了很长的过期时间。用户关闭 计算机电源,回家后再次启动计算机并访问其 路由器的管理界面 http://router.example,该界面嵌入了 /popular-library.js。恶意脚本在管理界面的第一方上下文中加载。
这些攻击都不新颖——它们只是此规范局限性的示例。
潜在缓解措施 需要注意到网络变化并 清除特定于先前网络的状态。以完全通用的方式做到这一点 很可能是不可能的,除非清除所有状态。也许可以 达成一个实际的折中。见 wicg/private-network-access issue #28。
一种替代方法可能是将权限授予限定到一个 能区分不同网络的标识符。
5.5. 本地网络攻击者
在本地网络访问检查应用到所有指向
local 地址空间的跨源请求之前,本地
网络上的恶意服务器可能(1)攻击本地网络上的其他服务器,
以及(2)攻击运行在用户机器上 localhost 的
服务。(1)即使不滥用用户浏览器也已经可能发生,
但(2)仍是一个担忧。例如,强制门户可能能够将用户重定向到一个恶意
页面,该页面尝试探测和攻击运行在用户机器上的易受攻击的 localhost
服务。(另见 wicg/private-network-accesss
issue
#39。)
我们认为 drive-by Web 上的公共网站是更紧迫的安全(和 隐私)风险,并认为这些保护的增量推出是有价值的 进展,尽管来自本地网络攻击者的风险仍然存在。
5.6. HTTP 缓存
5.6.1. 将检查应用于子资源
缓存的子资源受此规范保护,因为 HTTP 缓存 会记住源 IP 地址,该地址可在 HTTP-network-or-cache fetch 期间的本地网络访问 检查算法中使用。
如果没有此检查,恶意公共网站可能能够确定 用户过去是否访问过特定私有网站。
由于 HTTP 缓存分区,子资源只能被 能够复制缓存条目的network partition key 的恶意攻击者从缓存加载。攻击者可以实现这一点的一种方式 是通过操纵 DNS(另见 § 5.2 DNS 重绑定),以便 冒充最初嵌入缓存资源的顶层站点。
用户代理导航到 http://router.example,它由 192.168.1.1 提供服务。该网站嵌入一个来自 http://router.example/$BRAND-logo.png 的 logo,并将其缓存。
恶意攻击者随后将 router.example 重新绑定到攻击者控制的 公共 IP 地址,并以某种方式诱使用户再次访问 http://router.example。恶意网站尝试嵌入该 logo, 并监控加载是否成功。如果成功,攻击者就确定了 用户路由器的品牌。
5.6.2. HTTP 缓存投毒
虽然此规范旨在保护本地网络服务器免于接收 来自公共网站的请求,但 DNS 重绑定可用于通过对未认证资源进行缓存投毒 来实施类似攻击。
伪装成 http://router.com 的攻击者可以在 http://router.com/totally-legit.js 缓存一个恶意脚本。之后,当用户导航到 http://router.com/ 时,页面可能请求被投毒的脚本并在更不公共的IP 地址空间中执行 攻击者代码。
此攻击由缓存分区部分缓解,因为这使得 攻击者必须先将顶层浏览上下文导航到 http://router.com/ 再缓存资源,这缺乏隐蔽性。它也 并非 Local Network Access 特有,而是明文 HTTP 缺乏认证和完整性保护的一个症状。
6. 致谢
非常感谢 Titouan Rigoudy、Jonathan Hao 和 Yifan Luo 提供的宝贵反馈和建议,他们参与了最初的 Private Network Access 提案 和规范工作,并慷慨地讨论了他们的工作,帮助头脑风暴 前进路径。