专用网络访问:简介

Titouan Rigoudy
Titouan Rigoudy
Yifan Luo
Yifan Luo

更新

  • 2022 年 7 月 7 日:更新了当前状态并新增了 IP 地址空间定义。
  • 2022 年 4 月 27 日:更新了时间表公告。
  • 2022 年 3 月 7 日:在 Chrome 98 中发现问题后宣布了回滚。

简介

按照专用网络访问 (PNA) 规范,Chrome 将弃用从公共网站直接访问专用网络端点的功能。

Chrome 将在针对子资源的任何专用网络请求之前发送 CORS 预检请求,以请求目标服务器明确授予的权限。此预检请求将携带新的标头 Access-Control-Request-Private-Network: true,而对其的响应必须带有相应的标头 Access-Control-Allow-Private-Network: true

这样做的目的是保护用户免受针对专用网络上的路由器和其他设备的跨站请求伪造 (CSRF) 攻击。这些攻击影响了数十万用户,使攻击者能够将其重定向到恶意服务器。

部署计划

Chrome 将分两个阶段推出这项变更,以便让网站有时间注意到这项变更并进行相应调整。

  1. 在 Chrome 104 中:

    • Chrome 通过先于专用网络子资源请求发送预检请求来进行实验。
    • 预检失败只会在开发者工具中显示警告,而不会影响专用网络请求。
    • Chrome 会收集兼容性数据,并与受影响最大的网站联系。
    • 我们希望这种做法能与现有网站广泛兼容。
  2. 最早在 Chrome 113 中:

    • 只有当兼容性数据表明变更足够安全,并且我们已在必要时直接主动联系时,才会开始迁移。
    • Chrome 会强制要求预检请求必须成功,否则请求失败。
    • 弃用试用会同时开始,以便受此阶段影响的网站可以申请延期。试用期至少会持续 6 个月。

什么是专用网络访问 (PNA)

专用网络访问(以前称为 CORS-RFC1918)限制了网站向专用网络上的服务器发送请求的能力。

Chrome 已实现部分规范:从 Chrome 96 开始,只允许安全上下文发出专用网络请求。如需了解详情,请参阅我们上一篇博文

该规范还扩展了跨域资源共享 (CORS) 协议,因此,网站现在必须先向专用网络上的服务器明确请求授权,然后才能发送任意请求。

PNA 如何对 IP 地址进行分类并识别专用网络

IP 地址分为三种 IP 地址空间: - public - private - local

本地 IP 地址空间包含的 IP 地址可以是 RFC1122 第 3.2.1.3 节中定义的 IPv4 环回地址 (127.0.0.0/8),也可以是 RFC4291 第 2.5.3 节中定义的 IPv6 环回地址 (::1/128)。

专用 IP 地址空间包含仅在当前网络中有意义的 IP 地址,包括 RFC1918 中定义的 10.0.0.0/8172.16.0.0/12192.168.0.0/16RFC3927 中定义的链路本地地址 169.254.0.0/16RFC4193 中定义的唯一本地 IPv6 单播地址 fc00::/7RFC4193 中定义的唯一本地 IPv6 单播地址,以及 RFC4193 中定义的唯一本地 IPv6 单播地址,以及 RFC4193 中定义的 RFC4 专用链接。fe80::/10RFC4291

公共 IP 地址空间包含之前未提及的所有其他地址。

本地 IP 地址被认为比专用 IP 地址更私密,后者被视为比公共 IP 地址更私密。

当可用性较高的网络将请求发送到可用性较低的网络时,请求属于专用请求。
专用网络访问 (CORS-RFC1918) 中公共、专用和本地网络之间的关系

有关详情,请参阅 Feedback Want: CORS for Private Networks (RFC1918)

预检请求

背景

预检请求是跨域资源共享 (CORS) 标准引入的机制,用于在向目标网站发送可能会产生副作用的 HTTP 请求之前从目标网站请求权限。这样可以确保目标服务器理解 CORS 协议,并显著降低 CSRF 攻击的风险。

权限请求以 OPTIONS HTTP 请求的形式发送,其中包含用于说明即将到来的 HTTP 请求的特定 CORS 请求标头。响应必须包含特定 CORS 响应标头,明确同意即将到来的请求。

表示 CORS 预检的序列图。系统会向目标发送 OPTIONS HTTP 请求,后者会返回 200 OK。然后发送 CORS 请求标头,并返回 CORS 响应标头

专用网络访问功能的新变化

为了预检请求,我们引入了一对新的请求和响应标头:

  • 所有 PNA 预检请求均已设置 Access-Control-Request-Private-Network: true
  • 必须为所有 PNA 预检响应设置 Access-Control-Allow-Private-Network: true

无论请求方法和模式如何,PNA 的预检请求都会针对所有专用网络请求发送。在 cors 模式、no-cors 和所有其他模式下,这些请求会在请求之前发送。这是因为所有专用网络请求都可用于 CSRF 攻击,而不考虑请求模式以及响应内容是否提供给发起者。

如果目标 IP 地址比发起者的私密性更高,系统也会为同源请求发送 PNA 预检请求。这与常规 CORS 不同,在常规 CORS 中,预检请求仅适用于跨源请求。同源请求的预检请求可防止 DNS 重新绑定攻击。

示例

可观察的行为取决于请求的模式

无 CORS 模式

假设 https://foo.example/index.html 嵌入 <img src="https://bar.example/cat.gif" alt="dancing cat"/>,而 bar.example 解析为 192.168.1.1,这是根据 RFC 1918 创建的专用 IP 地址。

Chrome 会先发送预检请求:

HTTP/1.1 OPTIONS /cat.gif
Origin: https://foo.example
Access-Control-Request-Private-Network: true

要成功完成该请求,服务器必须做出以下响应:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Private-Network: true

然后,Chrome 会发送实际请求:

HTTP/1.1 GET /cat.gif
...

服务器可以正常响应。

CORS 模式

假设 https://foo.example/index.html 运行以下代码:

await fetch('https://bar.example/delete-everything', {
  method: 'PUT',
  credentials: 'include',
})

同样,假设 bar.example 解析为 192.168.1.1

Chrome 会先发送预检请求:

HTTP/1.1 OPTIONS /delete-everything
Origin: https://foo.example
Access-Control-Request-Method: PUT
Access-Control-Request-Credentials: true
Access-Control-Request-Private-Network: true

要成功完成该请求,服务器必须做出以下响应:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Credentials: true
Access-Control-Allow-Private-Network: true

然后,Chrome 会发送实际请求:

HTTP/1.1 PUT /delete-everything
Origin: https://foo.example

按照常规 CORS 规则,服务器可以做出响应:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://foo.example

如何确定您的网站是否受到影响

从 Chrome 104 开始,如果检测到专用网络请求,系统会在该请求之前发送预检请求。如果此预检请求失败,系统仍会发送最终请求,但在开发者工具的“问题”面板中会显示警告。

Devtools Issues 面板中的预检请求失败警告。此声明:确保仅向允许专用网络请求的资源发出专用网络请求,并发送有关特定请求的详细信息,并列出受影响的资源。

您也可以在网络面板中查看和诊断受影响的预检请求:

对于 localhost,开发者工具 Network 面板中失败的预检请求会显示 501 状态。

如果您的请求会在没有专用网络访问规则的情况下触发常规 CORS 预检,则网络面板中可能会显示两项预检,其中第一项预检始终显示为已失败。这是一个已知 bug,您可以放心地忽略它。

在开发者工具的 Network 面板中,预检成功之前假装失败的预检请求。

如需了解强制执行预检成功后会有什么影响,您可以传递以下命令行参数(从 Chrome 98 开始):

--enable-features=PrivateNetworkAccessRespectPreflightResults

任何失败的预检请求都会导致提取失败。这样,您就可以测试您的网站在部署计划的第二阶段后能否正常工作。诊断错误的方式与使用上述开发者工具面板诊断警告的方式相同。

网站受到影响时该怎么做

这项变更在 Chrome 104 中推出后,应该不会破坏任何网站。不过,我们强烈建议您更新受影响的请求路径,以确保您的网站继续按预期运行。

有两种解决方案可供您使用:

  1. 在服务器端处理预检请求
  2. 使用企业政策停用 PNA 检查

在服务器端处理预检请求

更新任何受影响的提取的目标服务器,以处理 PNA 预检请求。首先,在受影响的路由上实现对标准 CORS 预检请求的支持。然后添加对两个新响应标头的支持。

当您的服务器收到预检请求(带有 CORS 标头的 OPTIONS 请求)时,服务器应检查是否存在 Access-Control-Request-Private-Network: true 标头。如果此标头存在于请求中,服务器应检查 Origin 标头和请求路径以及任何其他相关信息(例如 Access-Control-Request-Headers),以确保可以安全地允许请求。 通常,您应允许访问受您控制的单个源站。

服务器决定允许请求后,应使用必要的 CORS 标头和新的 PNA 标头来响应 204 No Content(或 200 OK)。这些头文件包括 Access-Control-Allow-OriginAccess-Control-Allow-Private-Network: true 以及根据需要的其他头文件。

请参阅示例,了解具体场景。

使用企业政策停用专用网络访问通道检查

如果您对用户拥有管理控制权,则可以使用以下任一政策停用专用网络访问通道检查:

有关详情,请参阅了解 Chrome 政策管理

向我们提供反馈

如果您是在接收公共网络请求的专用网络中托管网站,Chrome 团队有兴趣了解您的反馈和用例。如需告知我们,请在 crbug.com 上向 Chromium 提交问题,并将该组件设为 Blink>SecurityFeature>CORS>PrivateNetworkAccess

后续步骤

接下来,Chrome 将扩展专用网络访问权限检查,以涵盖网页工作器:专用工作器、共享工作器和 Service Worker。我们的目标是让 Chrome 107 开始显示警告

然后,Chrome 将扩展专用网络访问通道检查,以涵盖导航(包括 iframe 和弹出式窗口)。我们暂不努力让 Chrome 108 开始显示警告。

在这两种情况下,我们会谨慎地进行类似的分阶段部署,以便为 Web 开发者留出时间调整和估算兼容性风险。

致谢

封面照片由 Mark OlsenUnsplash 用户发布。