Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >深入了解 CORS

深入了解 CORS

原创
作者头像
写bug的高哈哈
修改于 2024-11-20 02:22:12
修改于 2024-11-20 02:22:12
2160
举报

“好事”文章推荐:计算机中的文件系统-崩溃恢复机制讲解

文章介绍了操作系统文件系统崩溃恢复机制,包括概念、日志系统特性,详细讲解了 xv6 文件系统写入文件操作步骤、各步骤功能及崩溃恢复情况,还指出 xv6 存在的问题及后续将介绍 Ext3 文件系统。


这篇文章将会带你了解 CORS (Cross-Origin Resource Sharing) 的概念和设置方法,确保您的网站能在遵守同源政策的前提下正确处理跨域请求。学习如何设置 Access-Control-Allow-Methods、Access-Control-Allow-Headers、Access-Control-Allow-Origin 等 header,以及在使用 cookie 时的额外设置。

同源政策 (Same-Origin Policy)


首先我们来认识浏览器的「同源政策」。

大家应该都有用过浏览器提供的 fetch API 或 XMLHttpRequest 等方式,让我们通过 JavaScript 获取资源。常见的应用是向后端 API 获取数据再呈现在前端。

需要注意的是,用 JavaScript 通过 fetch API 或 XMLHttpRequest 等方式发起请求,必须遵守同源政策 (same-origin policy)

什么是同源政策呢?简单地说,用 JavaScript 访问资源时,如果是同源的情况下,访问不会受到限制;

然而,在同源政策下,非同源的请求则会因为安全性的考量受到限制。浏览器会强制你遵守 CORS (Cross-Origin Resource Sharing,跨域资源访问) 的规范,否则浏览器会让请求失败。

什么是同源?

那什么情况是同源,什么情况不是呢?所谓的同源,必须满足以下三个条件:

  1. 相同的通讯协议,即 http/https
  2. 相同的域名
  3. 相同的端口

举例:下列哪个与 https://example.com/a.html 为同源?

跨域请求

不是同源的情况下,就会产生一个跨域 http 请求(cross-origin http请求)。

举个例子,例如我想要在 https://bugbug.io 的页面上显示来自 https://othersite.com 的数据,于是我利用浏览器的 fetch API 发送一个请求:

代码语言:js
AI代码解释
复制
try {
  fetch('https://othersite.com/data')
} catch (err) {
  console.error(err);
}

这时候就产生了一个跨域请求。而跨域请求必须遵守 CORS 的规范。

服务器没有正确设置时,请求就会因为违反 CORS 而失败,在 Chrome DevTool 就会看到以下的经典错误:

代码语言:txt
AI代码解释
复制
Access to fetch at *** from origin *** has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

我们接下来就一起来看 CORS 到底是什么,又该如何正确地设置 CORS 吧!

什么是 CORS (Cross-Origin Resource Sharing)?


终于要进入重点了,到底什么是 CORS?

简单地说,CORS (Cross-Origin Resource Sharing) 是针对不同源的请求而定的规范,通过 JavaScript 访问非同源资源时,后端服务必须明确告知浏览器允许何种请求,只有后端服务允许的请求能够被浏览器实际发送,否则会失败。

在 CORS 的规范里面,跨域请求有分两种:「简单」的请求和非「简单」的请求。

接下来会分别解释两种请求的 CORS 分别如何运行的。

简单跨域请求


所谓的「简单」请求,必须符合下面两个条件:

  1. 只能是 HTTP GET, POST or HEAD 方法
  2. 自定义的请求header 只能是 AcceptAccept-LanguageContent-LanguageContent-Type(值只能是 application/x-www-form-urlencodedmultipart/form-datatext/plain)。细节可以看 fetch spec

不符合以上任一条件的请求就是非简单请求。

举个例子来说,下面这个请求不是一个简单的请求:

代码语言:txt
AI代码解释
复制
const response = await fetch('https://othersite.com/data', {
  method: 'DELETE',
  headers: {
    'Content-Type': 'application/json',
    'X-CUSTOM-HEADER': '123'
  }
});

违反简单请求的地方有三个,分别是:

  1. 他是 http DELETE 方法;
  2. 他的 Content-Type 是 application/json;
  3. 他带了不合规范的 X-CUSTOM-HEADER。

Origin (来源)

首先,浏览器发送跨域请求时,会带一个 Origin header,表示这个请求的来源。

Origin 包含通讯协议、域名和端口三个部分。

所以从 https://shubo.io 发出的往 https://othersite.com/data 的请求会像这样:

代码语言:txt
AI代码解释
复制
GET /data/
Host: othersite.com
Origin: https://shubo.io
...

Access-Control-Allow-Origin

当后端服务端收到这个跨域请求时,它可以依据「请求的来源」,即 Origin 的值,决定是否要允许这个跨域请求。如果后端服务允许这个跨域请求,它可以「授权」给这个来源的 JavaScript 访问这个资源。

授权的方法是在 response 里加上 Access-Control-Allow-Origin header:

代码语言:txt
AI代码解释
复制
Access-Control-Allow-Origin: https://shubo.io

如果后端服务允许任何来源的跨域请求,那可以直接回 *

代码语言:txt
AI代码解释
复制
Access-Control-Allow-Origin: *

当浏览器收到响应时,会检查请求中的 Origin header 是否符合响应的 Access-Control-Allow-Origin header,相符的情况下浏览器就会让这个请求成功,我们也可以顺利地用 JavaScript 读取到响应;反之,则浏览器会将这个请求视为是不安全的而让他失败,即便后端服务确实收到请求也成功地响应了,但基于安全性的原因 JavaScript 中没有办法读到响应。

JavaScript 默认可以访问的「简单」response header 有以下这些:

  • Cache-Control
  • Content-Language
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

如果要让 JavaScript 访问其他 header,后端服务端可以用 Access-Control-Expose-Headers header 设置。

代码语言:txt
AI代码解释
复制
X-MY-CUSTOM-HEADER: 123
X-MY-OTHER-CUSTOM-HEADER: 123
Access-Control-Expose-Headers: X-MY-CUSTOM-HEADER, X-MY-OTHER-CUSTOM-HEADER

一般跨域请求


非「简单」的跨域请求,例如:HTTP PUT/DELETE 方法,或是 Content-Type: application/json 等,浏览器在发送请求之前会先发送一个 「preflight请求(预检请求)」,其作用在于先询问服务器:你是否允许这样的请求?真的允许的话,我才会把请求完整发送过去。

Preflight Request (预检请求)

什么是 preflight请求呢?

Preflight请求是一个 http OPTIONS 方法,会带有两个请求header:Access-Control-Request-MethodAccess-Control-Request-Headers

  • Access-Control-Request-Method: 非「简单」跨域请求的 HTTP 方法。
  • Access-Control-Request-Headers 非「简单」跨域请求带有的非「简单」header。

比方说我发送的非「简单」跨域请求是这样:

代码语言:txt
AI代码解释
复制
fetch('https://othersite.com/data/', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CUSTOM-HEADER': '123'
  }
})

那我的请求header 会长得会像这样:

代码语言:txt
AI代码解释
复制
POST /data/
Host: othersite.com
Origin: https://shubo.io
Content-Type: application/json
X-MY-CUSTOM-HEADER: 123

浏览器帮我们发送的 preflight请求就会像这样:

代码语言:txt
AI代码解释
复制
OPTIONS /data/
Host: othersite.com
Origin: https://shubo.io
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-MY-CUSTOM-HEADER, Content-Type

Preflight Response

那收到 preflight请求时,后端服务该做什么呢?

后端服务必须告诉浏览器:我允许的方法和 header 有哪些。因此 后端服务的响应必须带有以下两个 header:

  • Access-Control-Allow-Methods: 允许的 HTTP 方法。
  • Access-Control-Allow-Headers: 允许的非「简单」header。

当浏览器看到跨域请求的方法和 header 都有被列在允许的方法和 header 中,就表示可以实际发送请求了!

以上面提到例子来说,如果后端服务可以接受上述的请求,后端服务的 preflight response 应该要像这样:

代码语言:txt
AI代码解释
复制
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: X-MY-CUSTOM-HEADER, Content-Type

浏览器收到正确的 preflight response,表示 CORS 的验证通过,就可以送出跨域请求了!

接下来,浏览器实际帮我们送出以下的跨域请求:

代码语言:txt
AI代码解释
复制
POST /data/
Host: othersite.com
Origin: https://shubo.io
Content-Type: application/json
X-MY-CUSTOM-HEADER: 123

最后一步,后端服务还是要响应 Access-Control-Allow-Origin header。浏览器会再检查一次跨域请求的响应是否带有正确的 Access-Control-Allow-Origin header:

代码语言:txt
AI代码解释
复制
Access-Control-Allow-Origin: https://shubo.io

这一步也检查无误的话,我们的跨域请求才算正式成功喔!这时候我们才能在 JavaScript 中读取响应的内容:

代码语言:txt
AI代码解释
复制
fetch('https://othersite.com/data/', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CUSTOM-HEADER': '123'
  }
})
.then(response => response.json())
.then(json => {
  console.log(json);
});

跨域请求的 Cookie


一般的 http 请求会带有该域名底下的 cookie;然而,跨域请求默认是不能带 cookie 的。

为什么呢?因为带有 cookie 的请求非常强大,如果请求携带的 cookie 是 session token,那这个请求可以以你的身份做很多危险的事情,像是访问你的隐私数据、从你的银行帐户转帐等。所以浏览器端针对跨域请求的 cookie 也做了规范。

首先,请求必须要明确地标示「我要访问跨域 cookie」。使用 fetch API 和 XMLHttpRequest 的设置方法如下:

  • credentials

通过 fetch API 发送跨域请求,需要设置 credentials: 'include'

代码语言:txt
AI代码解释
复制
fetch('https://othersite.com/data', {
  credentials: 'include'
})
  • withCredentials

通过 XMLHttpRequest 发送跨域请求,需要设置 withCredentials = true;

代码语言:txt
AI代码解释
复制
const xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.open('POST', 'https://othersite.com/data');

如此一来跨域请求就会携带 cookie 了!

后端服务也需要额外的设置:如果是信任的来源,响应要带有 Access-Control-Allow-Credentials header:

代码语言:txt
AI代码解释
复制
Access-Control-Allow-Credentials: true

如此一来,浏览器才会将 cookie 写进该域名。

注意:如果是允许使用 cookie 的情况,**Access-Control-Allow-Origin* __不能用 **`****,必须明确标示哪些来源允许访问。** 理由也是基于安全性考量,因为可以用 cookie 的情况下,通常表示会访问一些比较个人化的数据,假设任何网站都能够访问这样的数据,显然是有点危险的!所以不能设为*`!

如果你偷懒地用了 Access-Control-Allow-Origin: *,就会无情地收到来自浏览器的错误:

代码语言:txt
AI代码解释
复制
The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when therequest's credentials mode is 'include'. Origin http://localhost:8080 is therefore not allowed access. Thecredentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

总结


遇到 CORS 的问题,可以归纳出这样的 SOP:

  1. 先认清楚是否为「简单」的跨域请求,如果是,在后端 GET/POST/HEAD 方法本身加上 Access-Control-Allow-Origin header。
  2. 如果非「简单」跨域请求,在后端 OPTIONS 加上 Access-Control-Allow-MethodsAccess-Control-Allow-Headers header。另外,在后端方法本身加上 Access-Control-Allow-Origin header。
  3. (Optional) 需要使用 cookie 的情况下,前端要加上 credentials: 'include' 或是 withCredentials 参数,后端要加上 Access-Control-Allow-Credentials header,而且 Access-Control-Allow-Origin header 不能用 *

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
CORS
CORS(https://links.jianshu.com/go?to=https%3A%2F%2Fdeveloper.mozilla.org%2Fzh- CN%2Fdocs%2FGlossary%
ruochen
2021/12/04
3.1K0
怎样与 CORS 和 cookie 打交道[每日前端夜话0x4A]
CORS 与 cookie 在前端是个非常重要的问题,不过在大多数情况下,因为前后端的 domain 一般是相同的,所以很少去关心这些问题。或者只是要求后端设置 Access-Control-Allow-Origin: * 就行了,很少去了解背后运作的机制。
疯狂的技术宅
2019/04/23
1.4K0
怎样与 CORS 和 cookie 打交道[每日前端夜话0x4A]
CORS讲解
跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。
Vincent-yuan
2019/09/10
2K0
CORS讲解
CORS攻击原理介绍和使用
注意:本文分享给安全从业人员,网站开发人员和运维人员在日常工作中使用和防范恶意攻击,请勿恶意使用下面描述技术进行非法操作。
全栈工程师修炼指南
2020/10/23
6.6K0
CORS攻击原理介绍和使用
asp.net core 系列之允许跨域访问-1(Enable Cross-Origin Requests:CORS)
AddPolicy 在StartUp.ConfigureServices方法中调用;对于一些选项,先阅读一下,CORS是怎么工作的,可能会有帮助
Vincent-yuan
2019/09/10
2.7K0
HTTP访问控制(CORS)
跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。
acc8226
2022/05/17
1.3K0
跨域共享CORS详解及Gin配置跨域
跨域简介 当两个域具有相同的协议(如http), 相同的端口(如80),相同的host,那么我们就可以认为它们是相同的域(协议,域名,端口都必须相同)。 跨域就指着协议,域名,端口不一致,出于安全考虑,跨域的资源之间是无法交互的(例如一般情况跨域的JavaScript无法交互,当然有很多解决跨域的方案) 解决跨域几种方案 /* CORS 普通跨域请求:只服务端设置Access-Control-Allow-Origin即可, 前端无须设置,若要带cookie请求:前后端都需要设置。
iginkgo18
2020/12/01
1.8K0
CORS原理及@koa/cors源码解析
这是浏览器的同源策略所造成的,同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。
木子星兮
2020/07/16
1.3K0
SpringBoot使用CORS解决跨域请求问题
同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。 同源策略是浏览器安全的基石。
朝雨忆轻尘
2019/06/19
6.4K0
15 张精美动图全面讲解 CORS
前言: 本文翻译自 Lydia Hallie[1] 小姐姐写的 ✋?? CS Visualized: CORS[2],她用了大量的动图去解释 CORS 这个概念,国内还没有人翻译本文,所以我在原文的理
卤代烃
2020/08/07
1.2K0
跟我一起探索 HTTP-跨源资源共享(CORS)
跨源资源共享CORS,是一种基于HTTP头的机制,该机制通过允许服务器标示除了它自己以外的其他源(域、协议或端口),使得浏览器允许这些源访问加载自己的资源。跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的“预检”请求。在预检中,浏览器发送的头中标示有 HTTP 方法和真实请求中会用到的头。
用户1418987
2023/10/16
6410
跟我一起探索 HTTP-跨源资源共享(CORS)
【网络知识补习】❄️| 由浅入深了解HTTP(五)跨源资源共享(CORS)
跨源资源共享 (CORS) (或通俗地译为跨域资源共享)是一种基于HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其它origin(域,协议和端口),这样浏览器可以访问加载这些资源。跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的"预检"请求。在预检中,浏览器发送的头中标示有HTTP方法和真实请求中会用到的头。
呆呆敲代码的小Y
2021/08/20
1.5K0
【网络知识补习】❄️| 由浅入深了解HTTP(五)跨源资源共享(CORS)
HTTP的同源策略与跨域资源共享(CORS)机制
准确的说,同源策略是指,浏览器内部在发起如下请求时,该来源必须是当前同源的HTTP资源:
用户7657330
2020/08/14
1.5K0
HTTP的同源策略与跨域资源共享(CORS)机制
HTTP访问控制(CORS)
跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。
JavaEdge
2020/05/27
3.7K0
HTTP访问控制(CORS)
系统服务化构建-跨域CROS
文本讨论关于接口开发中的跨域 CORS。CORS 是一种浏览器协议,源于 HTTP 请求的安全策略,在这个体系中的关键词有,同源策略,XMLHttpRequest,Ajax,和前后端分离。
needrunning
2019/12/10
1.1K0
系统服务化构建-跨域CROS
对象存储COS跨域CORS问题小结
CORS(Cross-origin resource sharing) 中文名称"跨域资源共享",由于安全原因,Web 应用程序默认情况只能在同源(协议、域名和端口)的情况下向服务器获取数据。
吴硕卫
2020/11/19
9.7K0
对象存储COS跨域CORS问题小结
10 种CORS跨域解决方案
这是一个老生常谈的话题,以前我觉得这种基础文章没有什么好写的,最近为了线上问题深入了解底层,确实有点东西,下面汇总成10种方案。
sunsky
2022/09/09
7.3K0
10 种CORS跨域解决方案
【安全】899- 前端安全之同源策略、CSRF 和 CORS
你之所以会遇到 跨域问题,正是因为 SOP 的各种限制。但是具体来说限制了什么呢?
pingan8787
2021/04/07
1.5K0
【安全】899- 前端安全之同源策略、CSRF 和 CORS
跨域资源共享 CORS 错误解析及解决方法
我们通常会利用CORS机制实现跨域接口服务的访问,为了简便开发环境、测试环境等不同环境的配置,通常大家会用*通配符标识允许任意域名的请求。但是在需要发送Cookie等身份凭证的情况,用*通配符会出现一些错误
DamonLiu
2022/05/08
14.8K0
跨域资源共享 CORS 详解
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能
ruanyf
2018/04/12
1.1K0
跨域资源共享 CORS 详解
相关推荐
CORS
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档