详解浏览器同源策略和跨资源共享CORS


浏览器同源策略

同源策略是浏览器的一种安全策略。目前所有浏览器都施实行这个策略,这是由网景公司(NetScape)1995年引入的。

定义

同源是指的三个相同,简单来说就是:协议相同域名相同端口相同,如果这三者有任一不同,则会受到同源策略的限制,包括但不限于读取Cookie

举个栗子:这个网站http://www.godrry.com/archives/why-cant-you-admit-youre-wrong.html

  • 协议是http://
  • 域名是www.godrry.com
  • 端口是80,当然80是默认端口,可以省略

它的同源情况可能有以下几种:

http://www.godrry.com/category/life/    => [同源]
http://my.godrry.com/category/life/    =>[域名不同]
https://www.godrry.com/category/life/    =>[协议不同]
http://www.godrry.com:6670/category/life/    =>[端口不同]

意义

浏览器的同源策略是一种保护,它必须要约束好不同源网站之间的联系,确保他们能够正常工作且互相不打扰。比如我们在a网站登录,登录信息存储在Cookie中,此时我们又打开了B网站,那么如果不约束A和B之间的关系,那么B就有可能读取到A中的Cookie,用户的信息安全就会受到威胁。

限制

![XurRR](/Users/gaoce/Downloads/XurRR.gif)

![](/Users/gaoce/Downloads/opRrw.gif)

如果非同源,则会有以下限制

  • 无法获取DOM
  • 无法读取CookieLocalStorageIndexDB
  • 无法发送Ajax请求

相对来说,这些限制保证了用户的信息安全,约束了网站之间的行为,但是有时候可能也会带来一些不便。所以我们有一些方法可以绕过同源策略的限制。接下来我们就来聊一聊如何不受同源策略的限制发送Ajax请求。


跨域资源共享CORS

![](/Users/gaoce/Downloads/0_heiz7awNkQ1B0O8e.png)

CORS:全称cross-origin resource sharing,属于W3C制定的标准,用于允许浏览器向跨源服务器发出XML请求,丰富了Ajax的应用场景。这其实是现代浏览器调整政策,放松了同源策略。

参与者

浏览器服务器是CORS的主要参与者,浏览器要支持CORS才能够发出请求和接收响应,而跨源服务器则要实现CORS接口。目前所有的浏览器都支持CORS(IE不低于10),当浏览器发现此次请求属于跨源请求,则会自动添加一些附带的请求头,有时候还会进行一次预请求;跨源服务器则要通过配置才能够实现CORS接口。

在两者中,跨源服务器的配置属于关键。

CORS请求分为2种

CORS请求分为 简单请求 和 非简单请求,浏览器的处理方式并不相同。

简单请求

如果一次请求满足以下两大条件,那么这个请求就属于简单请求(如果不满足则属于非简单请求):

  • 请求方法限于:HEAD,GET,POST
  • HTTP的头部信息限于:Accept,Accept-Language,Content-Language,Last-Event-ID,Content-Type
  • Content-Type限于:application/x-www-form-urlencodedmultipart/form-datatext/plain

Last-Event-ID头信息,浏览器发送这个请求头用来帮助服务器端重建连接。

浏览器在发送CORS请求时,如果发现这是一个跨源简单请求,会在请求头中添加Origin字段,告诉服务器这次请求来自于哪里,其值包括请求源的协议域名端口。服务器根据请求头中的Origin来判断是否许可这次请求。

许可请求:

服务器会在响应头中添加

Access-Control-Allow-Origin: http://www.godrry.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: Godrry
  • Access-Control-Allow-Origin 表示允许跨源请求的域名,一般会有2种值,一是发出请求的域名,一是*代表允许所有域名跨源请求。【必选】
  • Access-Control-Allow-Credentials表示是否将响应内容暴露给请求源,响应内容包括cookies, authorization headers 或 TLS client certificates , 设置为true则表示允许,不设置则为false,但不允许设置false,所以如果你需要它为true就设置,不需要则可以忽略该字段。【可选】

另外,CORS请求默认不发送Cookie和HTTP认证信息,所以如果要在XML请求时携带这些信息,则需要配置下属性

let xhr = new XMLHttpRequest()
xhr.withCredentials = true

如果要发送Cookie,那么服务器响应头中的Access-Control-Allow-Origin就不能设置为* ,必须明确指定与请求源同源的域名,此时的Cookie信息依然受到同源策略的限制,只有服务器域名设置的Cookie才会随请求发送,另外document.cookie是无法读取到这段Cookie信息

  • Access-Control-Expose-Headers 表示是否暴露其他响应头给请求源,默认包括Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma,这些都可以通过XML的getResponseHeader()方法拿到,但是如果你需要暴露其他响应字段给请求源,那么就需要指定一下哪些响应头。像上面设置Access-Control-Expose-Headers: Godrry,那么Godrry响应头就可以通过getResponseHeader('Godrry')拿到它的值。【可选】

不许可请求:

服务器通过请求头中的Origin字段,判断不许可该请求,那么服务器也会给予响应,但是不会包含Access-Control-Allow-Origin字段,当浏览器接收到这个响应并没有发现该响应头时抛出错误,XMLHttpRequest的onerror事件捕获错误。注意此时服务器返回的Status Code有可能是200,所以无法据此判断是否请求成功。

非简单请求

如果浏览器发现本次请求不是简单请求,那么非简单请求会包含两个请求:预检请求和正式请求。当然如果预检请求不通过,则不会进行真正的请求。

预检请求(preflight)

浏览器会在正式请求前发送一个预检请求,用来咨询服务器此次请求是否被许可,许可内容包括Origin、请求方式(动词)和请求头。

接下来我们发送一个非简单请求,向服务器example.godrry.com,请求动词为PUT,并且设置一个自定义请求头:

let xhr = new XMLHttpRequest()
xhr.open('PUT','http://example.godrry.com')
xhr.setRequestHeader('My-Custom-Header', 'bingo')
xhr.send()

浏览器发送预检请求(请求动词为OPTION),设置以下请求头告知服务器正式请求的请求动词和额外的头信息字段等,

Access-Control-Request-Headers: content-type,my-custom-header
Access-Control-Request-Method: PUT
Origin: http://demo.godrry.com
...

如果服务器许可此次请求,则会有以下响应头信息:

access-control-allow-headers: content-type,my-custom-header
access-control-allow-methods: GET,HEAD,PUT,PATCH,POST,DELETE
access-control-allow-origin: *
  • access-control-allow-origin 表示服务器许可谁进行CORS,也可以设置为 *
  • access-control-allow-methods 表示服务器许可CORS的请求方式
  • access-control-allow-headers 表示服务器许可CORS的所有头信息

接下来浏览器就会发送出正式请求,正式请求就像简单请求一样,在请求头信息中添加Origin ,服务器的响应头信息中也需要一直携带Access-Control-Allow-Origin 。如果再次请求还会进行预检,如果希望预检通过后再次请求时省略预检这一步,可以由服务器设置Access-Control-Max-Age字段,设置预检请求有效期。

如果服务器不许可此次请求,那响应头信息中没有相关CORS字段,则浏览器会抛出一个错误,由XML的onerror事件捕获。浏览器控制台也会打印出相关错误。

WechatIMG2.png

声明:GodGc's World|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - 详解浏览器同源策略和跨资源共享CORS


軟件工程沒有銀彈