Home CORS 跨域问题
Post
Cancel

CORS 跨域问题

CORS 跨域资源共享 (cross-originresource sharing)

是一个W3C标准,允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制,

1.SOP(Same Origin Policy)同源策略

浏览器同源策略是,浏览器安全的基石,由Netscape公司引入浏览器。基本内容是指,如果非同源,以下的一些操作无法完成

  • Cookie,LocalStorage,IndexDB,无法读取
  • DOM无法获取
  • AJAX请求不能发送 同源主要指三个方面
  • 协议相同:http https
  • 域名相同:
  • 端口相同:

同源政策的目的是为了保障用户信息安全,防止恶意的网站窃取数据,但是在一些情况下,也不是那么方便。目前而言,可以从服务端和客户端(浏览器)来解决。

2.跨文档通讯API(Cross-document messaging)

H5规范内,引入一种新的跨源信息读取方式,可以跨源获取当前不同网页上的数据,主要方式为

Window.PostMessage(message,location),接受端,可以通过监听Message事件来进行数据的获取,

3.AJAX内处理解决同源策略

AJAX请求只能发送给同源的网站,否则会报错,除了服务器架设代理外

  • JSONP
  • WebSocket
  • CORS
3.1 JSONP 服务器和客户端之间的跨源通讯

在网页内,添加一个<script>标签,通过这个script标签,向服务器发起请求,服务器在接收到请求后,将数据放在一个指定名字的回调函数里传回来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//添加<script>标签
function addScriptTag(src) {
  var script = document.createElement('script');
  script.setAttribute("type","text/javascript");
  script.src = src;
  document.body.appendChild(script);
}

window.onload = function () {
  addScriptTag('http://example.com/ip?callback=foo');
}

//相应的返回函数,
function foo(data) {
  console.log('Your public IP address is: ' + data.ip);
};

<script>元素请求的脚本,直接作为代码进行运行,作为参数的数据被视为JavaScript对象,而不是字符串。避免了被同源策略限制。

3.2 WebSocket

WebSocket是一种通讯协议(本质上也是应用层的一种协议,和 HTTP 同级别,但是目前使用,一般是在HTTP 基础上来使用 WebSocket协议),使用ws://wss://作为协议前缀,不实行同源策略

3.3 CORS 跨域资源共享

CORS是一个标准,运行浏览器向跨源服务器发出 XMLHttpRequest请求。

CORS通讯过程,由浏览器自动完成,不需要用户进行相关的处理。浏览器发现了跨源请求,就会自动添加附加头部信息。CORS的关键是服务器,只要服务器实现了CORS接口就可以实现跨源通讯。

CORS请求分为 简单请求非简单请求

简单请求:

  • 请求方法为:HEAD GET POST
  • 请求头信息不超出:
    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type:只限于三个值application/x-www-form-urlencodedmultipart/form-datatext/plain

简单请求,浏览器发出CORS请求,只需要在头部添加一个origin字段。用来说明请求来自的协议、域名、端口。

1
2
3
4
5
6
GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

如果origin字段内的源,没有在允许范围内,服务器就会返回一个正确回应,但是没有Access-Control-Allow-Origin字段,从而抛出错误。而如果在允许返回内,服务器会多几个头信息字段

1
2
3
4
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8
  • Access-Control-Allow-Origin:必须字段,为*或者 origin的值
  • Access-Control-Allow-Credentials:可选,是否允许发送Cookies,默认Cookies不包括在CORS请求内,如果要发送Cookies,就不能将上一个字段设置为*

(3)Access-Control-Expose-Headers

该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。上面的例子指定,getResponseHeader('FooBar')可以返回FooBar字段的值。


复杂请求:针对服务器有特殊要求,请求方法为PUT DELETE,或者请求的Content-Typeapplication/json

复杂请求在正式通信前,会增加一次HTTP查询请求(请求方式为OPTIONS),称为预检,浏览器先询问服务器是否可以发送。

1
2
3
4
5
6
7
8
OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

同源策略虽然很厉害,但是浏览器中仍然存在一些不受制于其影响的 api、标签,例如常见的ImgiframeScript 标签,即不受到同源信息策略的限制。

在实际书写 img 标签时,可能在对应 src 上,编写对应的 json 请求 url,那么就可能产生,服务器跨域返回数据。

CORB (Cross-Origin Read Blocking)跨源读取阻碍

在加载可以进行跨源的资源是,在资源载入页面之前,对其进行识别和拦截的算法。对浏览器的渲染进行进行保护

an algorithm by which dubious cross-origin resource loads may be identified and blocked by web browsers before they reach the web page.

浏览器在加载可以跨域资源时,在资源载入页面之前,对其进行识别和拦截的算法。

哪些内容受CORB保护

当前有三种内容类型受保护,分别是jsonhtmlxml。关于如何针对每种内容类型 CORB 如何对其进行保护,文档中有详细的章节进行介绍,规则均是对内容格式进行一些有针对性的校验,以确认它确实是某个内容类型。这个校验结果最终影响 CORB 的运作方式。

CORB如何起作用

CORB会对响应内容为上诉三种数据的response进行保护,具体如下:

CORB 会根据如下步骤来确定是否对 response 进行保护(如果响应的内容格式是 json、html 或者 xml):

  • 如果 response 包含 X-Content-Type-Options: nosniff 响应头部,那么如果 Content-Type 是以下几种的话, response 将受 CORB 保护:
    • html mime type
    • xml mime type(除了 image/svg+xml)
    • json mime type
    • text/plain
  • 如果 response 的状态是 206,那么如果 Content-Type 是以下几种的话, response 将受 CORB 保护:
    • html mime type
    • xml mime type(除了 image/svg+xml)
    • json mime type
  • 否则,CORB 将尝试探测 response 的 body:
    • html mime type,并且探测结果是 html 内容格式,response 受 CORB 保护
    • xml mime type(除了 image/svg+xml), 并且探测结果是 xml 内容格式,response 受 CORB 保护
    • json mime type,并且探测结果是 json 内容格式,response 受 CORB 保护
    • text/plain,并且探测结果是 json、html 或者 xml 内容格式,response 受 CORB 保护
    • 任何以 JSON security prefix 开头的 response(除了 text/css)受 CORB 保护

这里值得一提的是,对于探测是必须的,以防拦截了那些依赖被错误标记的跨源响应的页面(比如,图片资源但是格式却被标记为 text/html)。如果不进行格式探测,那么会有16倍以上的 response 被拦截。

CORB 如何拦截一个响应

当一个 response 被 CORB 保护时,它的 body 会被覆盖为空,同时 headers 也会被移除(当前 Chrome 仍然会保留 Access-Control-* 相关的 headers)。

关于 CORB 的工作方式,一定要和 CORS 做区分,因为它要防止这些被拦截的数据进入渲染当前页面进程的内存中,所以它一定不会被加载并读取。这不同于 CORS,因为后者会做一些过滤操作,数据虽然不可被加载,但是可能仍然保留在渲染进程的内存中。


参考文章: 30 分钟理解 CORB 是什么 - SegmentFault 思否 跨域资源共享 CORS 详解 - 阮一峰的网络日志 (ruanyifeng.com)

This post is licensed under CC BY 4.0 by the author.

谷歌 CSS、HTML 书写规范简要记录

JVM(深入理解JVM 虚拟机 读书笔记)