CORS 是 Cross-origin resource sharing 的简称,中文名叫:跨域资源共享。
这是一个在 Web 安全领域很重要的模型。
它解决的问题是,如何在不同域下安全地共享资源。
1. 背景
前端的编写十分灵活,这得益于 JavaScript 语言表达的灵活性。但是,正所谓能力越大,责任越大,这种灵活性也会给 Web 安全带来诸多挑战。默认情况下,网页主动发起的 HTTP 请求(链接跳转不算),例如 XMLHttpRequest
和 Fetch API
,只支持 同源策略(Same Origin Policy)🔗,即只能访问当前域下的资源。
http://example-a.com/
访问 http://example-b.com/
下的资源就是跨域,请求会失败。
这在一定程度上缓解了恶意代码执行的风险。
同样也会带来一些问题:如果确实有些资源在另一个域下,怎么获取?
CORS 就是用来解决这个问题的。
2. 功能
当一个域下的网页想要访问另一个域下资源时,如果对方服务端响应的报头(HTTP header)包含正确的 CORS 信息,浏览器便不会拦截,跨域资源顺利获取。
简单来说,CORS 是一组协议,允许服务端指定哪些主机可以访问本地资源。
这便是 CORS 的全部内容。
CORS 是 HTTP 标准的一部分,因此得到了现代浏览器的广泛支持。
老的浏览器可以用 JSONP🔗 的方式实现跨域访问。这是一个很有意思的 workaround,借助浏览器本身提供的特性“绕”过了同源限制。但这不是一个规范实现,容易引发安全问题,因此在现代浏览器上,最好使用 CORS。
2.1 CORS 标头
HTTP 标头中有一系列 CORS 相关的。
参考:跨源资源共享 - MDN Web 文档术语表:Web 相关术语的定义 | MDN🔗。
当检测到跨域请求时,浏览器会默认添加相应的请求头,响应头则需要开发者在服务端设置。
2.2 工作流程
主要的阶段分为三个:
对于跨域访问,浏览器会填充 Origin
头,例如:
服务端收到请求,就会加上 Access-Control-Allow-Origin
指定允许的源,或者 *
允许所有访问。
浏览器拿到响应,判断 Access-Control-Allow-Origin
里的字段是否匹配,匹配即可拿到结果,否则报错。
2.3 场景
使用的场景主要有三个:
- 简单请求
- 预检请求(preflight)
- 附带身份凭证
简单请求通常需要满足两个条件。
- 使用的方法是下列之一
- 允许设置的 HTTP 头字段
- Accept
- Accept-Language
- Content-Language
- Content-Type(text/plain, multipart/form-data, application/x-www-form-urlencoded)
- Range(只允许简单的范围标头值 如 bytes=256- 或 bytes=127-255)
一次简单请求:
请求报文:
服务器响应:
因为 Access-Control-Allow-Origin: *
允许所有跨域访问,于是这次请求会成功响应。
与简单请求不同,预检请求需要两次访问。这些工作是浏览器自动做的。
第一次是先发送 OPTIONS
请求到服务端,检查是否允许,允许的话才会继续发送真实请求。
预检请求的例子:
因为请求的 Content-Type
是 application/xml
,所以会触发预检。
首次交互结果:
允许访问后发送实际请求:
预检请求之所以会有两次,是因为这里的请求可能改变服务端状态,因此需要一次试探性地询问。有点像是 两阶段提交🔗。
默认的跨域访问,不会携带身份信息,不过允许设置,指定 withCredentials
为 true
,请求时会附带 Cookies
。
交互过程如下:
返回结果中如果缺少 Access-Control-Allow-Credentials: true
,响应会失败。
3. 实际使用
在前端开发中,多数情况都是使用本域下的资源,安全,可控。
但不排除有时需要访问第三方资源,此时就需要格外注意 CORS 可能带来的问题。
对数据保护严格的网站,会设置苛刻的 CORS 策略,从而导致请求失败。
这个在 Console 窗口里很容易观察到。
尽可能少的使用外部资源,出现问题了能轻松应对,了解到这个层面,差不多就够了。
4. 总结
在计算机领域里,权衡(trade-off)无处不在。
允许访问资源,但需要满足条件,提高了安全性的同时,也不可避免地降低了开发效率。
任务解决方案都是一体两面,或许这就是技术世界的辩证。
(完)
参考
- 浏览器的同源策略 - Web 安全 | MDN🔗
- JSONP - 维基百科,自由的百科全书🔗
- 跨源资源共享 - MDN Web 文档术语表:Web 相关术语的定义 | MDN🔗
- Cross-origin resource sharing - Wikipedia🔗
- Cross-Origin Resource Sharing (CORS) - HTTP | MDN🔗
在 GitHub 上编辑本页面 最后更新于: 2024-11-20T09:44:17+08:00