同源策略与CORS

作者: 聪明的奇瑞 | 来源:发表于2017-12-29 10:00 被阅读244次

同源策略

  • 它是浏览器最核心也是最基本的安全功能,浏览器的同源策略,限制了来自不同的 “document” 或脚本对当前的 “document” 的读取或设置某些属性
  • 如果没有同源策略,可能 a.com 的一段 Javascript 脚本在 b.com 未曾加载此脚本时,也可以随意涂改 b.com 的页面,为了不发生页面行为混乱,浏览器提出 ”Origin” 这一概念,来自不同 Origin 的对象互不干扰。
  • 影响 Origin(源) 的因素有:host(域名或IP)、子域名、端口、协议:
URL OutCome Reason
http://store.company.com/dir2/other.html Success
http://store.company.com/dir/inner/anthoer.html Success
https://store.company.com/secure.html Failure Different protocol
http://store.company.com:81/dir/etc.html Failure Different port
http://news.company.com/dir/other.html Failure Different host
  • 在浏览器中 <script><img><iframe><link> 等标签都可以跨域加载资源,而不受到同源策略的限制。这些带 “src” 属性的标签每次加载时,实际上是由浏览器发起了一次GET请求。不同于 XMLHttpRequest 的是,通过 src 属性加载的资源,浏览器限制了 JavaScript 的权限,使其不能读、写返回内容
  • XMLHttpRequest 可以访问同源资源,一开始不能跨域访问,但随着互联网发展,W3C制定了 XMLHttpRequest 跨域访问的标准(CORS),它需要通过目标与返回的HTTP头来授权是否可以跨域访问,因为HTTP头对于 JavaScript 来说一般无法控制
  • 但是浏览器的同源策略并非坚不可摧,如 IE8 的 Css 跨域漏洞:
www.a.com/test.html:
    <body>
    {}body{font-family:
    aaaaaaaaaaaaaaa
    bbbbbbbbbbbbbbbbb
    </body>
www.b.com/test2.html:
    <style>
    @import url("http://www.a.com/test.html")
    </style>
    <script>
        setTimeout(function(){
            var t = document.body.currentStyle.fontFamily;
            alert(t);
        },2000);
    </script>
  • 上述代码中 www.b.com/test2.html 中通过 @import 加载了 www.a.com/test.html 为 Css 渲染进入当前页面 DOM,同时通过 document.body.currentStyle.fontFamily 访问此内容,问题在 IE 的 CSS Parse 过程中,IE 将 fontFamily 后面的内容当做 value,而通过 <script> 等标签仅能加载资源,不能读写资源内容,而这个漏洞能够跨域读取页面内容,绕过了同源策略

CORS

  • CORS 是 W3C 制定的“跨域资源共享”的标准,它允许浏览器向跨源服务器发出 XMLHttpRequest 请求,克服了 AJAX 只能同源的使用限制
  • CORS 需要浏览器和服务器同时支持,目前所有浏览器都支持该功能,IE 浏览器不能低于 IE10,整个通信过程是浏览器自动完成的,不需要用户参与,CORS 与 AJAX 代码上没有差别,浏览器一旦发现 AJAX 请求跨源,就会自动添加一些附加的头信息
  • 因此实现 CORS 的通信关键是服务器,只要服务器实现了 CORS 接口,就可以跨源通信

两种请求

  • 浏览器将 CORS 请求分为两类:简单请求(Simple Request)和非简单请求(not-so-simple reuqest)
  • 只要满足以下两种条件就属于简单请求,否则属于非简单请求
请求方法是以下三种方法之一:
    HEAD、GET、POST
HTTP的头信息不超出以下几种字段:
    Accept、Accept-Language、Content-Language、Last-Event-ID
    Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

简单请求

  • 对于简单请求,浏览器直接发出 CORS 请求,就是在头信息中添加一个 Origin 字段
  • 下面是浏览器在一个请求中添加 Origin 字段的例子
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 字段用来说明本次请求来自哪个源(协议+域名+端口),服务器根据这个值,决定是否同意本次请求
  • 如果 Origin 指定的源不在许可范围内,服务器会返回一个正常的 HTTP 协议,但头信息没有包含 Access-Control-Allow-Origin 字段,从而抛出一个错误,被 XMLHttpRequest的onerror 回调函数捕获。注意,这种错误无法通过状态码识别,因为 HTTP 回应的状态码有可能是200
  • 如果 Origin 指定的域名在许可范围内,服务器的响应会多出几个头信息
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:该字段可选,它是一个布尔值,表示是否允许发送 Cookie
  • Access-Control-Expose-Headers:该字段可选,CORS 请求时,XMLHttpRequest 对象的 getResponseHeader() 方法只能拿到 6 个基本字段:ache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果想拿到其它字段就必须在 Access-Control-Expose-Headers 里面指定,上面例子指定了 getResponseHeader('FooBar') 可以返回 FooBar 字段的值

withCredentials 属性

  • CORS 请求默认不发送 Cookie 和 HTTP 认证信息,如果要把 Cookie 发送到服务器,一方面要服务器同意
Access-Control-Allow-Credentials = true
  • 另一方面开发者必须在 AJAX 请求中打开 withCredentials 属性
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
  • 有些浏览器会默认一起发送 Cookie,这时可以显式关闭 withCredentials
xhr.withCredentials = false;
  • 如果要发送 Cookie,Access-Control-Allow-Origin 就不能为星号,必须指定明确的、与请求网页一致的域名,并且 Cookie 依然遵循同源策略

非简单请求

  • 非简单请求是那种对服务器有特殊需求的请求,比如 PUT 或 DELETE 方法,或者 Content-Type 字段的类型是 application/json
  • 非简单请求的 CORS 请求会在正式通信之前增加一次 HTTP 请求查询,称为“预检”请求
  • 浏览器会先询问服务器,当前网页是否在服务器的许可名单中,以及可以使用那些 HTTP 动词和头字段信息,只有得到肯定大幅,浏览器才会发送 XMLHttpRequest 请求,否则报错
  • 下面是一段浏览器的 JS 脚本
var url = 'http://api.alice.com/cors';
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.setRequestHeader('X-Custom-Header', 'value');
xhr.send();
  • 上面代码 HTTP 请求方法是 PUT,并且发送一个自定义的头信息 X-Custom-Header
  • 浏览器发现,这是一个非简单请求,就自动发出一个“预检”请求,要求服务器确认,下面是一个“预检”请求的例子
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...
  • “预检”请求的方法是 OPTIONS,表示这个请求是用来询问的,头信息里关键字段是 Origin,表示来自哪个源
  • 除了 Origin 字段,还包括两个特殊字段
    • Access-Control-Request-Method:必须,用来列出 CORS 请求用的 HTTP 方法,上例是 PUT
    • Access-Control-Request-Headers:该字段是一个逗号分离的字符串,指定额外发送的头字段信息,上例是 X-Custom-Header

预检请求的回应

  • 服务器收到“预检”请求后检查 Origin、Access-Control-Request-Method、Access-Control-Request-Headers 字段后确认允许跨源请求,就可以作出回应
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
  • 上面例子中 Access-Control-Allow-Origin 字段表示 http://api.bob.com 可以请求数据,该字段也可以为星号,表示同意任意跨源请求
Access-Control-Allow-Origin: *
  • 如果浏览器否定了“预检”请求会返回一个正常的 HTTP 回应,但不包含 CORS 相关头信息,因此会触发一个错误,被 XMLHttpRequest 对象的 onerror 回调函数捕获
  • 服务器回应的其它 CORS 相关字段如下:
Access-Control-Allow-Methods: GET, POST, PUT  #表示支持的跨域请求方法
Access-Control-Allow-Headers: X-Custom-Header  #表示服务器支持的所有头信息字段
Access-Control-Allow-Credentials: true  #该字段与简单请求时相同
Access-Control-Max-Age: 1728000  #指定本次预检请求的有效期,单位为秒,即在缓存该条回应期间,不用在发出另一条预检请求

相关文章

  • 同源策略与CORS

    同源策略 同源策略是浏览器保护用户安全上网的重要措施,协议、域名、端口号三者相同即为同源。 不同源下,浏览器不允许...

  • 同源策略与CORS

    浏览器的同源策略#### 同源策略限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。 一个源的定义##...

  • 同源策略与CORS

    同源策略 它是浏览器最核心也是最基本的安全功能,浏览器的同源策略,限制了来自不同的 “document” 或脚本对...

  • 跨域

    主要内容: 同源策略、跨域实现形式(JSONP、CORS、降域、postMessage) 同源策略 (Same o...

  • day07-前端面试技巧-(通讯)

    什么是同源策略及限制 前后端如何通讯: Ajax:同源下的通讯方式 webSocket:不受限制同源策略 cors...

  • Spring Boot中通过CORS解决跨域问题

    Spring Boot中通过CORS解决跨域问题 同源策略 同源策略是由Netscape提出的一个著名的安全策略,...

  • SpringBoot2.x整合CORS解决跨域问题

    跨域问题系列文章 1. 同源策略与CORS(跨域请求的起源)2. SpringBoot2.x整合CORS解决跨域问...

  • 同源策略以及CORS

    同源策略 只有协议+端口+域名都一模一样,才允许发AJAX请求!一模一样一模一样一模一样! http://baid...

  • 同源策略与 CORS 跨域

    一、同源策略 同源策略:浏览器出于安全方面的考虑,只允许与本域下的接口交互。不同源的客户端脚本在没有明确授权的情况...

  • django-cors-headers 跨域问题

    django-cors-headers ''' 浏览器具有 "同源策略的限制",导致 `发送ajax请求` + `...

网友评论

    本文标题:同源策略与CORS

    本文链接:https://www.haomeiwen.com/subject/cpfigxtx.html