什么是CORS

本文详细介绍了CORS(跨源资源共享)的概念及其工作原理。包括Origin的定义、Same-Origin Security Policy的安全策略、CORS的基本流程和服务端处理方式等内容。

英文原文来自我的GitHub页面

CORS = Cross-Origin Resource Sharing

什么是 Origin

要理解CORS,首先得理解什么是 “Origin”。参见RFC6454:如果两个URI拥有相同的schema,host和port,我们就认为他们是来自于相同的Origin。以下是一个完整的URI的定义:

    scheme:[//[user[:password]@]host[:port]][/path][?query][#fragment]

Same-Origin Security Policy

Same-origin security policy 是对客户端的要求。在这个要求之下,网络浏览器 对来自于相同Origin的脚本允许网页间相互访问。

这里有一个违反这个约定而造成的风险Wikipedia:

Assume that a user is visiting a banking website and doesn’t log out. Then, the user goes to another site that has some malicious JavaScript code running in the background that requests data from the banking site. Because the user is still logged in on the banking site, the malicious code could do anything the user could do on the banking site. For example, it could get a list of the user’s last transactions, create a new transaction, etc. This is because the browser can send and receive session cookies to the banking site based on the domain of the banking site.

Cross-Origin Resource Sharing

CORS是一种协议,它用来约定服务端和客户端那些行为是被服务端允许的。尽管服务端是可以进行验证和认证的,但基本上这是由客户端浏览器来保证的。这些对行为的允许是放在应答包的header里面的。

工作原理

CORS的实现主要包括一些客户端的工作以及两类服务端的处理,基本流程如下图所示:
Basic Workflow

客户端

下图来自 Wikipedia Click here to visit Wikipedia
Client Workflow

服务端 (简单 CORS 请求)
前提

只对满足以下所有条件的HTTP请求做出相应的CORS回应:
1. HTTP 方法仅限于 GET, POSTHEAD.
2. 客户端清秀需要含有 Origin 头.
3. 如果客户端请求是 POST,头部 Content-Type 只可以是 application/x-www-form-urlencoded, multipart/form-data, 或 text/plain.

业务逻辑

如果origin被服务端允许,服务端返回请求是带有 Access-Controll-Allow-Origin 头, 并且这个头部信息的值和客户端Origin 的值保持一致;否则就表示不被允许。如果 Access-Controll-Allow-Origin 被设置成 "*",则意味着任何Origin都被允许。

注意:如果所访问的资源需要凭证,那么 Access-Controll-Allow-Origin 则不应该被设置为 "*" 而且 Access-Control-Allow-Credentials 头需要被设置成 true.

示例

客户端HTTP 请求

GET /api/version HTTP/1.1
User-Agent: Fiddler
Accept: application/json
Origin: http://foo.origin

服务端回应

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Date: Wed, 31 Nov 2100 19:42:00 GMT
Server: Apache-Coyote/1.1
Content-Length: 53
Connection: keep-alive
Access-Control-Allow-Origin: http://foo.origin

[response payload]
服务端(预备请求)
前提

对满足任意以下条件之一的HTTP请求做出回应:
1. HTTP请求不是 GET, POSTHEAD.
2. 客户端请求带有自定义头部
3. 如果客户端请求是 POST, 头部 Content-Type 不是 application/x-www-form-urlencoded, multipart/form-data, or text/plain.

客户端进一步请求

客户端浏览器需要进行额外的 OPTIONS 请求,并且使用以下头部信息来向服务端问询相应的HTTP方法是否被允许:
1. Origin: Javascript的Origin
2. Access-Control-Request-Method: 准备使用的 HTTP 方法
3. Access-Control-Request-Headers: 将要在上述HTTP方法中使用的自定义头部

业务逻辑

如果请求不被允许,服务端返回4XX错误。
如果请求被允许,服务端返回200并在头部包含以下信息:
1. Access-Control-Allow-Origin: 被允许的Origin。如果Origin是个列表,则每个Origin之间用 "," 隔开。
2. Access-Control-Allow-Methods: 被允许的HTTP方法,如果是多个,用 "," 隔开。
3. Access-Control-Max-Age: 一个整数,用来表达这个预备请求什么时候过期,单位是
4. Access-Control-Allow-Credentials: 可选,如果所访问资源需要凭证,这个头部需要被设置成 true

示例

客户端HTTP请求

OPTIONS /resources/31415926
User-Agent: Fiddler
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: origin, x-requested-with, accept
Origin: http://foo.origin

服务端回应

HTTP/1.1 200 OK
Date: Wed, 20 Nov 2013 19:36:00 GMT
Server: Apache-Coyote/1.1
Content-Length: 0
Connection: keep-alive
Access-Control-Allow-Origin: http://foo.client.com
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE
Access-Control-Max-Age: 50000

参考文献

<think>我们正在讨论CORS的基本概念、工作原理,以及为什么有时未设置crossOrigin也能加载资源。以下将分步骤解释: ### 一、CORS 是什么? CORS(跨域资源共享)是一种浏览器安全机制,用于管理不同源(域、协议、端口)之间的资源请求[^1][^2]。其核心是**通过HTTP头部协商**,决定是否允许跨域访问。 #### 关键术语: - **同源策略**:浏览器默认禁止脚本跨域读取资源(如通过XMLHttpRequest或Fetch API)。 - **简单请求 vs 预检请求**: - **简单请求**:满足特定条件(如GET/HEAD/POST方法,且Content-Type为`text/plain`、`multipart/form-data`、`application/x-www-form-urlencoded`)[^2]。 - **预检请求**:复杂请求前发送OPTIONS请求,检查服务器是否支持跨域。 ### 二、CORS 如何工作? ```mermaid sequenceDiagram participant Browser participant Server Note over Browser: 跨域请求(如fetch('https://api.example/data')) Browser->>Server: 发送请求(自动添加Origin头) alt 简单请求 Server-->>Browser: 响应包含 Access-Control-Allow-Origin: * else 预检请求 Browser->>Server: OPTIONS请求(含Origin、Access-Control-Request-Method等头) Server-->>Browser: 响应包含 ACAO、ACAM等头 Browser->>Server: 正式请求 Server-->>Browser: 实际数据 end Browser: 校验ACAO匹配则返回数据,否则报错 ``` #### 关键响应头: - `Access-Control-Allow-Origin: *` 或 `https://your-domain.com` - `Access-Control-Allow-Methods: GET, POST`(预检响应) - `Access-Control-Allow-Headers: Content-Type`(预检响应) ### 三、为什么未设置 `crossOrigin` 也能加载资源? #### 场景:地图瓦片(`<img>`标签) 1. **未设置 `crossOrigin` 属性**: - 浏览器视为**普通跨域请求**,不触发CORS校验[^1]。 - 即使服务器返回`Access-Control-Allow-Origin: *`,浏览器也**不检查该头**。 - 资源正常加载,但**脚本无法读取像素数据**(如Canvas绘图会报错)。 2. **设置 `crossOrigin="anonymous"`**: - 浏览器添加`Origin`头并检查ACAO响应头。 - 若ACAO匹配(如`*`或当前域),则允许脚本读取资源内容。 #### 示例代码对比: ```html <!-- 无CORS检查:可显示图片,但Canvas操作报错 --> <img src="https://tile-server.com/map.png"> <!-- 触发CORS检查:需服务器返回有效ACAO --> <img src="https://tile-server.com/map.png" crossOrigin="anonymous"> ``` ### 四、核心区别总结 | 场景 | 是否发送`Origin`头 | 是否校验ACAO | 脚本能否读取资源内容 | |---------------------|-------------------|-------------|-------------------| | 未设`crossOrigin` | ❌ | ❌ | ❌(安全限制) | | 设置`crossOrigin` | ✔️ | ✔️ | ✔️(通过校验时) | > 因此,**未设置 `crossOrigin` 时浏览器忽略ACAO头**,是设计使然——避免破坏旧网站兼容性[^1][^2]。 --- ### 相关问题 1. 如何在Canvas中安全地绘制跨域图片? 2. 为什么预检请求需要OPTIONS方法? 3. 如何配置Nginx支持CORS? 4. 哪些HTTP方法会被视为“简单请求”?</think>### CORS(跨域资源共享)基本概念与工作原理 #### 一、CORS 是什么? CORS 是一种基于 HTTP 头部的安全机制,允许 Web 应用突破浏览器的**同源策略**限制,实现跨域资源访问[^1][^2]。其核心是通过服务器声明哪些外部域有权访问自己的资源。 **同源策略示例**: - 同源: `https://example.com/page1` 和 `https://example.com/page2` - 不同源: `https://example.com` 和 `https://api.example.com`(子域不同) - 不同源: `http://example.com` 和 `https://example.com`(协议不同) #### 二、CORS 工作原理 ```mermaid sequenceDiagram participant 浏览器 participant 服务器 浏览器->>服务器: 发送跨域请求(含 Origin 头) Note right of 服务器: 检查 Origin 是否在允许列表 服务器-->>浏览器: 返回响应(含 ACAO 头) Note left of 浏览器: 校验 ACAO 与 Origin 匹配 alt 匹配成功 浏览器-->用户: 返回资源数据 else 匹配失败 浏览器-->用户: 抛出 CORS 错误 end ``` ##### 关键 HTTP 头部: 1. **请求头**: - `Origin: https://your-site.com`(浏览器自动添加) 2. **响应头**: - `Access-Control-Allow-Origin: *`(允许所有域) - `Access-Control-Allow-Methods: GET, POST`(允许的 HTTP 方法) - `Access-Control-Allow-Headers: Content-Type`(允许的自定义头) ##### 工作流程: 1. **简单请求**(如 GET/POST)直接发送,浏览器检查 ACAO 2. **复杂请求**(如 PUT/DELETE)先发送 OPTIONS 预检请求 ```http OPTIONS /resource HTTP/1.1 Origin: https://your-site.com Access-Control-Request-Method: DELETE ``` #### 三、未设置 `crossOrigin` 也能加载资源的原因 以地图瓦片(`<img>` 标签)为例: 1. **未声明跨域需求**: ```html <!-- 未设置 crossOrigin 属性 --> <img src="https://tile-server.org/map.png"> ``` - 浏览器**不发送** `Origin` 头 - 服务器返回的 ACAO 头被**静默忽略** - 资源可加载,但脚本无法读取像素数据(安全限制) 2. **声明跨域需求时**: ```html <!-- 设置 crossOrigin 属性 --> <img src="https://tile-server.org/map.png" crossOrigin="anonymous"> ``` - 浏览器发送 `Origin` 头 - 严格校验 ACAO 头(值必须匹配或为 `*`) #### 四、核心差异总结 | 场景 | 是否发送 Origin | 是否校验 ACAO | 脚本能否读取资源内容 | |----------------------|----------------|--------------|-------------------| | 未设 `crossOrigin` | ❌ | ❌ | ❌(安全限制) | | 设置 `crossOrigin` | ✔️ | ✔️ | ✔️(通过校验时) | > **本质原因**:浏览器采用 "opt-in" 策略。未显式声明跨域时,为避免破坏旧网站兼容性,即使服务器返回无效 CORS 头也会放行基础加载[^1][^2]。 --- ### 相关问题 1. 如何在 Canvas 中安全地使用跨域图片? 2. 为什么预检请求(OPTIONS)是 CORS 的必要环节? 3. 如何配置 Nginx 服务器正确处理 CORS 请求? 4. `Access-Control-Allow-Credentials` 头在什么场景下必须使用?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值