目录javascript
CORS跨域资源共享html
简单跨域请求java
非简单请求python
CORS的安全问题linux
有关于浏览器的同源策略和如何跨域获取资源,传送门——> 浏览器同源策略和跨域的实现方法程序员
同源策略(SOP)限制了应用程序之间的信息共享,而且仅容许在托管应用程序的域内共享。这有效防止了系统机密信息的泄露。但与此同时,也带来了另外的问题。随着Web应用程序和微服务使用的日益增加,出于实用目的每每须要将信息从一个子域传递到另外一个子域,或者在不一样域之间进行传递(例如将访问令牌和会话标识符,传递给另外一个应用程序)。web
为了容许跨域通讯,开发人员必须使用不一样的技术来绕过SOP并传递敏感信息,以致于现今也成为了一个棘手的安全问题。所以,为了在不影响应用程序安全状态的状况下实现信息共享,在HTML5中引入了跨源资源共享(CORS)。但问题也随之而来,许多人为了方便干脆直接使用默认的配置,或是因为缺少对此的了解而致使了错误的配置。sql
跨域资源共享(CORS)是一种放宽同源策略的机制,它容许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制,以使不一样的网站能够跨域获取数据。json
咱们先来简单分析一下CORS跨域获取资源的过程:后端
CORS定义了两种跨域请求:简单请求 和 非简单请求。简单跨域请求就是使用设定的请求方式请求数据,而非简单跨域请求则是在使用设定的请求方式请求数据以前,先发送一个OPTIONS预检请求,验证请求源是否为服务端容许源。只有"预检"经过后才会再发送一次请求用于数据传输。
当咱们须要发送一个跨域请求的时候,浏览器会首先检查这个请求,若是它是简单跨域请求,浏览器就会马上发送这个请求。若是它是非简单跨域请求,这时候浏览器不会立刻发送这个请求,而是有一个跟服务器预检验证的过程。
(1) 请求方法是如下三种方法之一: HEAD GET POST (2)HTTP的头信息不超出如下几种字段: Accept Accept-Language Content-Language Last-Event-ID Content-Type:application/x-www-form-urlencoded、 multipart/form-data、text/plain
只有同时知足以上两个条件时,才是简单请求,不然为非简单请求。
浏览器判断该请求为简单请求时,会在Request Header中添加 Origin 字段,它表示咱们的请求源。
以下,简单请求头:
CORS服务端会将该字段做为跨源标志。CORS接收到这次请求后, 首先会判断Origin是否在容许源(由服务端决定)范围以内。
若是Origin指定的源在许可范围内,即验证经过,服务端会在Response Header 添加下面几个字段
Origin
字段的值,要么是一个*
,表示接受任意域名的请求。true时
,即表示服务器明确许可,Cookie能够包含在请求中,一块儿发给服务器。这个值也只能设为true
,若是服务器不要浏览器发送Cookie,删除该字段便可XMLHttpRequest
对象的getResponseHeader()
方法只能拿到6个基本字段:Cache-Control
、Content-Language
、Content-Type
、Expires
、Last-Modified
、Pragma
。若是想拿到其余字段,就必须在Access-Control-Expose-Headers
里面指定。以下,CROS服务端的回应:
若是Origin
指定的源不在许可范围内,即验证失败,服务器也会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息中的Access-Control-Allow-Origin
字段不包含访问源,就知道出错了,从而抛出同源检测异常的错误。注意,这种错误没法经过状态码识别,由于HTTP回应的状态码有多是200。
上面说到,CORS请求默认不发送Cookie和HTTP认证信息。若是要把Cookie发到服务器,一方面要服务器赞成,指定Access-Control-Allow-Credentials
字段。
Access-Control-Allow-Credentials:true
另外一方面,开发者必须在AJAX请求中打开withCredentials
属性
var xhr = new XMLHttpRequest(); xhr.withCredentials = true;
不然,即便服务器赞成浏览器发送Cookie,浏览器也不会发送。或者,服务器要求设置Cookie,浏览器也不会处理。
可是,若是省略withCredentials
设置,有的浏览器仍是会一块儿发送Cookie。这时,能够显式关闭withCredentials
xhr.withCredentials = false;
须要注意的是,若是要发送Cookie,即Access-Control-Allow-Credentials:true时,Access-Control-Allow-Origin
就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其余域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie
也没法读取服务器域名下的Cookie。
总结:简单请求只须要CORS服务端在接受到携带Origin字段的跨域请求后,在response header中添加Access-Control-Allow-Origin等字段给浏览器作同源判断。
非简单请求是那种对服务器有特殊要求的请求,好比请求方法是PUT
或DELETE
,或者Content-Type
字段的类型是application/json
。非简单请求的CORS请求,会在正式通讯以前,增长一次OPTIONS方法的预检请求。
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可使用哪些HTTP动词和头信息字段。只有获得确定答复,浏览器才会发出正式的XMLHttpRequest
请求,不然就报错。
下面简单分析一下非简单跨域请求的过程。浏览器先发送一个OPTIONS方法的预检请求。带有以下字段:
而后若是服务器配置了CORS,会返回对应对的字段,具体字段含义在返回结果是一并解释。
以下,OPTIONS预检的请求与相应
而后浏览器再根据服务器的返回值判断是否发送非简单请求。而后服务器处理完请求以后,会再返回结果中加上以下控制字段:
而后浏览器经过返回结果的这些控制字段来决定是将结果开放给客户端脚本读取仍是屏蔽掉。若是服务器没有配置CORS,返回结果没有控制字段,浏览器会屏蔽脚本对返回信息的读取,并报出同源检测异常的错误!
经过上面叙述,咱们得知借助CORS咱们没必要关心发出的请求是否跨域,浏览器会帮咱们处理这些事情,可是服务端须要支持CORS,服务端实现CORS的原理也很简单,在服务端彻底能够对请求作上下文处理,已达到接口容许跨域访问的目的。
固然,也有不少第三方的CORS插件,例如:Spring MVC 在4.2以上版本也支持了CORS配置,这样,服务端也无需本身操心了!
CORS很是有用,能够共享许多内容,不过这里存在风险。由于它彻底是一个盲目的协议,只是经过HTTP头来控制的。那么,CORS跨域资源共享漏洞是怎么发生的呢?因为程序员配置不当,Origin源不严格,从而形成跨域问题。
由以上可知,网站能够经过发送如下HTTP响应头部来启用CORS:
Access-Control-Allow-Origin: https://example.com
这样的话,就能够容许指定的源(http://example.com)来跨域请求服务器端的资源,而且服务器会响应。在默认状况下,发送跨域请求时不会携带cookie或其余凭据。所以,它不能用于窃取与用户相关的敏感信息(如CSRF令牌)。不过,网站服务器可使用如下头部来启用凭据传输:
Access-Control-Allow-Credentials:true
这样浏览器在请求数据的时候就须要带上cookie。
实现对单个域的信任是很是容易的事情。不过,若是须要信任多个域的话,那该怎么办呢?根据相关规范的建议,只需列出相关的域,并用空格加以分隔便可,例如:
Access-Control-Allow-Origin:http://a.example.com http://example.com
可是,没有哪一个浏览器真正支持这一特性。
因而,咱们能够经过使用通配符来信任全部子域,具体方法是:
Access-Control-Allow-Origin: *.example.com
但是有一些偷懒的程序员,将Access-Control-Allow-Origin设置为容许来自全部域*的跨域请求。
Access-Control-Allow-Origin:*
这样,全部的网站均可以对其进行跨域资源请求了,这是很是危险的。不过先别高兴的太早。其实这里在设计的时候有一个很好的限制。xmlhttprequest发送的请求须要使用 "withCredentials" 来带上Cookie,若是一个目标域设置成了容许任意域的跨域请求,这个请求又带着 Cookie 的话,这个请求是不合法的。(就是若是须要实现带 Cookie 的跨域请求,CORS服务端须要明确的配置容许来源的域,使用任意域的配置是不合法的)浏览器会屏蔽掉返回的结果。Javascript 就无法获取返回的数据了。这是CORS模型最后一道防线。假如没有这个限制的话,那么 Javascript 就能够获取返回数据中的 Cookie 和 CSRF Token,以及各类敏感数据。这个限制极大的下降了CORS的风险。
以下,这是不容许的:
Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true
这时,将在浏览器控制台中收到错误消息:当凭证标志为true时,没法在Access-Control-Allow-Origin中使用通配符(各个浏览器报错显示的不同)。
那么,CORS的漏洞到底出如今哪里呢?
1:CORS服务端的 Access-Control-Allow-Origin 设置为了 *,而且 Access-Control-Allow-Credentials 设置为false,这样任何网站均可以获取该服务端的任何数据了。
2:有一些网站的Access-Control-Allow-Origin他的设置并非固定的,而是根据用户跨域请求数据的Origin来定的。这时,无论Access-Control-Allow-Credentials 设置为了 true 仍是 false。任何网站均可以发起请求,并读取对这些请求的响应。意思就是任何一个网站均可以发送跨域请求来得到CORS服务端上的数据。
下面的代码是经过AJAX来跨域请求获取服务端的数据
<html lang="en"> <head> <meta charset="UTF-8"> <title>Ajax</title> <script type="text/javascript"> function foo(){ var xmlhttp=new XMLHttpRequest(); var url="http://127.0.0.1/1.txt"; //要跨域访问的资源 xmlhttp.open("POST",url,true); //xmlhttp.setRequestHeader('X-PINGOTHER','AAAA'); //自定义头部,若是这样的话,就属于非简单请求了 //xmlhttp.setRequestHeader('Content-Type','text/xml'); //自定义头部,若是这样的话,就属于非简单请求了 xmlhttp.send(); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { document.getElementById("my").innerHTML=xmlhttp.responseText; } } } </script> </head> <body> <button id="btn" οnclick="foo()">肯定</button> <p id="my">hello,word!</p> </body> </html>