0x01 前言
我们都知道,浏览器是遵循同源策略的,同源策略用来限制从一个源加载的文档或脚本如何与另一个源的的资源进行交互,这是一个用来隔离潜在的恶意文件的安全机制。
通常来说,浏览器是允许跨域写和跨域嵌入,但是跨域读取一般是不允许的,但是这样肯定是不方便的,因此后来有了话语资源共享,用来实现跨域读的功能。
0x02 跨域资源共享
跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是GET以外的 HTTP 请求,或者搭配某些 MIME 类型的POST请求)浏览器必须首先使用OPTION方法发起一个预检请求,从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括COOKIE和 HTTP 认证相关数据)。
0x03 简单请求与非简单请求
这里简单请求是指那些不会引起CORS预检请求的那种请求,而同理,非简单请求就是引起CORS预检请求。
简单请求
只要同时满足以下两大条件,就属于简单请求。
1 | (1) 请求方法是以下三种方法之一: |
当浏览器发现请求是简单请求的时候,就会在请求头部添加一个Origin字段,该字段表示本次请求属于哪个源的,服务器会根据这个字段的值来决定是否允许跨域访问。
如果服务器不允许这个源的访问,那么服务器发送的response中,就没有Access-Control-Allow-Origin字段,当浏览器发现返回的消息中没有该字段,就知道出错了,从而抛出错误
如果服务器这个源的访问,那么服务器发送的response中,就会多出几个以Access-Control开头的字段
- Access-Control-Allow-Origin
该字段是必须的,他表示允许访问的源,或者*,表示允许任意源访问。
- Access-Control-Allow-Credentials
该字段是一个boolen值,如果是true,则允许发送cookie到服务器
- Access-Control-Expose-Headers
CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定
非简单请求
不同时满足上面的条件的就是非简单请求。
非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为”预检”请求。
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的请求,否则就报错。
通常来说,预检请求是OPTION请求,在头信息中,包含着Origin字段,表示来自哪个源的。除了该字段,还有两个特殊的字段:
- Access-Control-Request-Method
该字段表示请求的方法是什么
- Access-Control-Request-Headers
该字段是一个逗号分隔的字符串,指定浏览器CORS请求中出现的额外字段名。
当服务器同意了这次请求之后会在响应中添加相应的字段:
- Acces-Control-Allow-Origin
该字段表示允许的源
- Access-Control-Allow-Method
该字段是必须的,是一个逗号分隔的字符串,表示服务器允许的跨域方法
- Access-Control-Allow-Headers
如果请求中有Access-Control-Request-Headers字段的话,响应中就会有该字段,是一个逗号分隔的字符串,用来表示服务器允许的字段名。
- Access-Control-Allow-Credentials
该字段也是用来表示服务器允许请求中包含cookie
- Access-Control-Max-Age
该字段表示本次预检请求的有效期,单位是秒。
但是如果服务器不允许请求,那么就会返回一个正常的HTTP Response给浏览器,浏览器发现响应中没有与CORS相关的字段,就知道服务器不允许这次请求,就会抛出错误。
0x04 参考文献
http://www.ruanyifeng.com/blog/2016/04/cors.html
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS