Chrome 重大更新,CORS 增加了两个新的请求头?

690次阅读  |  发布于2年以前

大家好, 今天我又来给大家解读浏览器策略了~

在刚刚发布的 Chrome 98 里面,有这样一项更新:

Chrome 将在任何对子资源的私有网络请求之前开始发送 CORS 预检请求,该请求需要目标服务器的明确许可。

啥?CORS 不是用来解决跨域的吗,跟私有网络有啥关系?啥是私有网络请求?

能问出这俩问题,一定没好好看我的公众号,其实之前在多篇文章里都提到过相关的策略解读,

Chrome 98 这个版本,对私有网络的限制正式生效啦,主要目的是保护用户免受针对私有网络上的路由器和其他设备的 CSRF 攻击。攻击者可以借助这个攻击方式将他们重定向到恶意服务器。

私有网络

私有网络请求指的是目标服务器的 IP 地址比请求发起者获取的 IP 地址更私密的请求。例如,从公共网站 (https://example.com) 到私人网站 (http://router.local) 的请求,或从私人网站到 localhost 的请求。

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

Chrome 已经实现了部分规范:从 Chrome 96 开始,只允许安全上下文发出私有网络请求。

预检请求

预检请求是跨域资源共享(CORS)标准引入的一种机制,用于在向目标网站发送可能有副作用的 HTTP 请求之前先向其请求一个许可。这确保了目标服务器理解 CORS 协议并显着降低了 CSRF 攻击的风险。

权限请求会作为 OPTIONS HTTP 请求发送,带有描述即将到来的 HTTP 请求的特定 CORS 请求标头(比如:Access-Control-Request-Method)。响应也必须携带明确同意即将到来的请求的特定 CORS 响应标头(比如:Access-Control-Allow-Origin)。

CORS 预检新增的两个 Header

为了限制私有网络请求,新增了两个 CORS 预检 Header

注意:无论请求方法和模式如何,都会为所有私有网络请求发送预检请求。这个请求在 cors 模式以及 no-cors 所有其他模式中的请求之前就已经发送了。

如果目标 IP 地址比发起请求的网址更私密,私有网络的预检请求也会针对同源请求发送。这和我们理解的常规 CORS 不一样,其中预检请求只会用于跨域请求。同源请求的预检请求还可防止 DNS 重新绑定攻击。

一个例子

在 NO-CORS 模式下

假设我们在 https://foo.example/index.html 嵌入了 <img src="https://conardli.example/cat.gif" alt="dancing cat"/> 并且, conardli.example 会解析为 私有 IP 地址 192.168.1.1

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

如果你设置了 Access-Control-Allow-Origin: *,也是可以请求成功的,不过这个风险较大,不建议设置。

在 CORS 模式下

假如我们在 https://foo.example/index.html 运行了下面的代码:

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

conardli.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 98 开始,如上面我们介绍的预检请求失败,请求依然会成功,但会在 DevTools 问题面板中显示一个警告。

受影响的预检请求也可以在 Network 面板中查看得到:

如果你想查看一下强制执行预检成功会发生什么,你可以改一下下面的命令行参数(从 Chrome 98 开始):

--enable-features=PrivateNetworkAccessRespectPreflightResults

具体的实施计划

Chrome 98 中:

最早在 Chrome 101 中:

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8