专用网络访问:简介

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 会在发送专用网络子资源请求之前发送预检请求,以进行实验。
    • 预检查失败仅会在 DevTools 中显示警告,不会以其他方式影响专用网络请求。
    • 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::/7RFC4291 第 2.5.6 节中定义的链路本地 IPv6 单播地址 fe80::/10,以及 IPv4 映射的 IPv6 地址(其中映射的 IPv4 地址本身是专用的)。

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

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

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

如需了解详情,请参阅期待收到反馈:专用网络的 CORS (RFC1918)

预检请求

背景

预检请求是 Cross-Origin Resource Sharing (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 问题面板中会显示一条警告。

在 Devtools 的“问题”面板中显示“预处理请求失败”警告。其中指出:确保仅向允许进行私有网络请求的资源发出此类请求,并附上有关具体请求和所列受影响资源的详细信息。

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

针对 localhost 的 DevTools 网络面板中的预检查请求失败,返回 501 状态。

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

在 DevTools 的“Network”面板中,成功的预检查前面出现了虚假的失败预检查请求。

如需了解在预检成功强制执行后会发生什么情况,您可以从 Chrome 98 开始传递以下命令行参数

--enable-features=PrivateNetworkAccessRespectPreflightResults

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

如果您的网站受到影响,该怎么办

此变更在 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 将扩展专用网络访问权限检查,以涵盖 Web Worker:专用工作器、共享工作器和 Service Worker。我们暂定计划在 Chrome 107 中开始显示警告。

然后,Chrome 会将专用网络访问检查扩展到涵盖导航,包括 iframe 和弹出式窗口。我们暂定在 Chrome 108 中开始显示警告。

在这两种情况下,我们将谨慎地采取类似的分阶段部署,以便给 Web 开发者有时间调整和评估兼容性风险。

致谢

封面照片由 Unsplash 用户 Mark Olsen 提供。