CORS 现代浏览器跨域请求简明手册

简介

本文主要是阐述与总结现代浏览器的跨域问题

同源策略

同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。

定义

如果两个 URL 的 protocol、port (en-US) (如果有指定的话)和 host 都相同的话,则这两个 URL 是同源。这个方案也被称为“协议/主机/端口元组”,或者直接是 “元组”。(“元组” 是指一组项目构成的整体,双重/三重/四重/五重/等的通用形式)。

下表给出了与 URL http://store.company.com/dir/page.html 的源进行对比的示例:

URL 结果 原因
http://store.company.com/dir2/other.html 同源 只有路径不同
http://store.company.com/dir/inner/another.html 同源 只有路径不同
https://store.company.com/secure.html 失败 协议不同
http://store.company.com:81/dir/etc.html 失败 端口不同 (http:// 默认端口是80)
http://news.company.com/dir/other.html 失败 主机不同

开始一个跨域请求

你可以使用XMLHttpRequestFetch发起一个跨域请求

你可以在网站http://foo.com发起一个对http://bar.com的请求,如果对方网站许可,那么便能拿到对应的响应,否则则失败。

请求分两类

预检请求

预检请求是一个OPTIONS 请求,在跨域时预先发送到服务端以获取该服务器对跨域访问控制的一些配置,以决定接下来的请求是否会被发送。一般以Header头的形式返回, 相关配置一般以Access-Control-*作为开头

实际请求

简单请求

简单请求不会触发CORS 预检请求

若请求满足所有下述条件,则该请求可视为”简单请求”:

  • 使用下列方法之一:
    • GET
    • HEAD
    • POST
  • 除了被用户代理自动设置的首部字段(例如 Connection, User-Agent)和在 Fetch 规范中定义为 禁用首部名称 的其他首部,允许人为设置的字段为 Fetch 规范定义的 对 CORS 安全的首部字段集合。该集合为:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type (需要注意额外的限制)
    • DPR
    • Downlink
    • Save-Data
    • Viewport-Width
    • Width
    • Content-Type 的值仅限于下列三者之一:
      • text/plain
      • multipart/form-data
      • application/x-www-form-urlencoded
  • 请求中的任意XMLHttpRequestUpload 对象均没有注册任何事件监听器;XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。
  • 请求中没有使用 ReadableStream 对象。

复杂请求

除了简单请求以外的所有请求都被称为复杂请求,复杂请求在进行跨域访问前会发送一个 CORS 预检请求

跨域请求响应Headers

跨域时携带Cookies

需要确保请求发起时信任对方

1
2
3
fetch('http://bar.com', {
credentials: 'include'
})

credentials 含义:

  • “omit”: Excludes credentials from this request, and causes any credentials sent back in the response to be ignored.
  • “same-origin”: Include credentials with requests made to same-origin URLs, and use any credentials sent back in responses from same-origin URLs.
  • “include”: Always includes credentials with this request, and always use any credentials sent back in the response.

1
2
3
4
5
const req = new XMLHttpRequest();
req.open('GET', url, true);
req.withCredentials = true;
req.onreadystatechange = handler;
req.send();

需要确保服务端响应头返回

1
Access-Control-Allow-Credentials: true

注意此时Access-Control-Allow-Origin不能为 “\“*

需要确保要发送的Cookie满足SameSite条件

注意Chrome 80 后将默认值从原来的None改为Lax, 相关影响可以看如下文章

参考文章

文章目录
  1. 1. 简介
  2. 2. 同源策略
    1. 2.0.1. 定义
  • 3. 开始一个跨域请求
  • 4. 请求分两类
    1. 4.1. 预检请求
    2. 4.2. 实际请求
      1. 4.2.1. 简单请求
      2. 4.2.2. 复杂请求
  • 5. 跨域请求响应Headers
  • 6. 跨域时携带Cookies
    1. 6.0.1. 需要确保请求发起时信任对方
    2. 6.0.2. 需要确保服务端响应头返回
    3. 6.0.3. 需要确保要发送的Cookie满足SameSite条件
  • 7. 参考文章