HTTP CORS

Cross-Origin Resource Sharing,跨域资源共享

基于同源策略,浏览器会限制由脚本发起的 cross-origin HTTP request。比如 XMLHttpRequest 和 Fetch API 都遵循 same-origin 策略,这意味着使用这些 API 的 Web 应用程序只能从 same-origin 请求资源,除非来自其它 origin 的 HTTP response 包含正确的 CORS header。

CORS 是一种基于 HTTP header 的机制,它能够让 Web server 自主地选择允许访问其资源的 cross-origin,浏览器以此为依据决定是否阻止前端 JavaScript 代码访问 cross-origin request 的 response。CORS 比简单地允许所有 cross-origin 请求更安全,比纯粹的同源请求有更多的自由度和功能。

Cross-Origin Sharing Standard 为以下场景启用 cross-origin HTTP request:

上下文
会启用 cross-origin HTTP 请求

JavaScript

  • XMLHttpRequest API 的调用

  • Fetch API 的调用

CSS

  • @font-face 使用 Web Font

  • shape-outside: url()

Canvas

drawImage() 绘制图像和视频

WebGL

texture

工作原理

CORS 标准的工作原理是添加新的 HTTP header,让服务器描述 Web 浏览器可以允许哪些 cross-origin 能访问自己。

CORS 还依赖于一种机制:预检请求。对于简单的 GET 请求,不会进行预检。对于可能对服务器数据产生副作用的 HTTP 请求方法,该规范要求浏览器预检请求。浏览器首先向 cross-origin 的资源发送一个 HTTP OPTIONS 请求,从服务器获得请求支持的方法,以检查服务器是否允许实际请求,在服务器批准后再发送实际请求。

在该预检请求中,浏览器发送指示 HTTP 方法的 header 以及将在实际请求中使用的 headers。服务器还可以通知客户端是否应随请求发送凭据,比如 cookie 和 HTTP 身份验证。

Request Header
Response Header

Origin

Access-Control-Allow-Origin

Access-Control-Request-Method Access-Control-Request-Headers

Access-Control-Allow-Methods Access-Control-Allow-Headers

Access-Control-Allow-Credentials Access-Control-Max-Age

Access-Control-Expose-Headers

OPTIONS /
Host: api.xxx.com                         # 要请求资源的 host
Origin: http://www.xxx.com                # 网站 parent 页面的 origin   *
Access-Control-Request-Method: POST       # 网站请求资源时的方法          *
# api.xxx.com 服务接受来自 http://www.xxx.com 的 cross-origin 请求
# api.xxx.com 服务使用 CORS 允许浏览器授权 http://www.xxx.com 向自己发出 cross-origin 请求
Access-Control-Allow-Origin: http://www.xxx.com
Access-Control-Allow-Methods: POST

Request header

  1. Origin

  2. Access-Control-Request-Method 实际请求将使用的 HTTP method

  3. Access-Control-Request-Headers 实际请求将使用的 HTTP headers(浏览器自取)

Origin 可用于预检请求、普通请求。在任何 access control request 中始终会发送 Origin header。

Access-Control-Request-* header 仅在预检请求中用到,即 HTTP OPTIONS,是支持 CORS 的浏览器帮我们设置的,在发送实际请求时并不会包含它们。也就是说,使用 cross-origin 功能(如 Fetch 或 XMLHttpRequest)的开发人员不用以编程的方式设置任何 cross-origin sharing request headers。

Response header

  1. Access-Control-Allow-Origin 重点介绍

  2. Access-Control-Allow-Methods

  3. Access-Control-Allow-Headers

  4. Access-Control-Allow-Credentials 重点介绍

  5. Access-Control-Max-Age 指示预检请求的结果可以缓存多长时间,单位是秒

  6. Access-Control-Expose-Headers 将指定的标头添加到允许 JavaScript 访问的白名单中

第2个和第3个都用于对预检 request 的 response。

Access-Control-Allow-Origin

取值,有两种情况:

Access-Control-Allow-Origin: <origin> | *

单 origin

虽然 <origin> 的值只能是单个 origin,但服务器通常会利用白名单让其值随 request Origin header 的值而动态改变。此时,response 会包含 Vary: Origin header 以说明服务器的动态策略。

Access-Control-Allow-Origin: https://xxx.com
Vary: Origin

* 通配符

Access-Control-Allow-Origin: * 适用于没有 credentials 的 request。此时,response 不会用任何 Set-Cookie header 设置 cookie。

credentials,凭证,最常见的是 Cookie header

凭据请求(credentialed request)带有 HTTP cookies 或 HTTP Authentication。

  • CORS 预检请求绝不能包含凭据

  • 对预检请求的响应必须指定 Access-Control-Allow-Credentials: true,才会在发实际请求的时候,使用凭据

  • 默认情况,在 cross-origin 的 XMLHttpRequest 或 Fetch 调用中,浏览器不会发送 credentials,除非 request 的 credentials 标志为 true

当响应 credentialed request 时,以下 header 的值一定不能是 *

  • Access-Control-Allow-Origin 的值只能是单个 origin

  • Access-Control-Allow-Methods 的值必须指定明确的 method name list

  • Access-Control-Allow-Headers 的值必须指定明确的 header name list

  • Access-Control-Expose-Headers 的值必须指定明确的 header name list

对于包含 credential 的 request:

  • 如果 request 包含 credential,且 response 包含 Access-Control-Allow-Origin: *,则浏览器会阻止访问 response,并在报告 CORS 错误

  • 如果 request 包含 credential,且 response 包含特定 origin Access-Control-Allow-Origin: https://xxx.com,则浏览器将允许该 origin 访问 response

Access-Control-Allow-Credentials

该 header 表示是否向 request 公开 response,当 request 的 credentials 标志为 true 时。

  • 当该 header 作为对预检请求的 response 时,表示实际请求是否可以带 HTTP credentials

  • 当该 header 作为对带 credentials 的 GET 请求的 response 时(因为简单的 GET 请求不会被预检),如果 response 没有随资源返回 Access-Control-Allow-Credentials header,则浏览器会忽略此 response,且不会把它返回给 web 内容

主要参考

  1. WHATWG Fetch spec: HTTP CORS protocol:该规范描述了 CORS 目前在浏览器中的实现方式

    • 现在,CORS 规范作为 WHATWG 的 Fetch Living Standard 的一部分包含在内

    • 2014 年 1 月,被接受为 W3C Recommendation

    • 2009 年 3 月,该草案更名为 Cross-Origin Resource Sharing

    • 2006 年 5 月,W3C 的 WebApps 工作组提交了第一份 W3C 工作草案

    • 2004 年 3 月,首次提出 cross-origin 支持,是允许 VoiceXML 浏览器进行安全的跨源数据请求

Last updated