CORS漏洞的学习与分析
同源策略
同源策略(Same origin policy)是一种约定,一种非常重要的安全措施,也是最基本的安全功能,它禁止了来自不同源的脚本对当前页面的读取或修改,从而限制了跨域访问甚至修改资源,防止出现A页面可以随意更改B页面信息这样子的极其糟糕的情况发生。
同源策略做了怎样的限制呢?怎样才会被认为是跨域的,不同源的呢?
以http://www.a.com为例:
正常情况 | http://www.a.com | 允许 |
不同域名 | http://www.b.com | 不允许 |
不同协议 | https://www.a.com | 不允许 |
不同端口 | http://www.a.com:10 | 不允许 |
不同子域名 | http://bp.a.com | 不允许 |
值得注意是:同源策略是在浏览器实现的所以它无法阻止请求和响应的发送,当跨域请求发起后,实际上已经接收到了所请求的资源,如果我们拦截来响应包,就可以发现,所请求的资源已经包含在响应的包中了,浏览器发现跨域,根据同源策略,浏览器不让所请求的资源加载出来。
hack.com将从test.com上请求数据
发现浏览器遵守同源策略阻止了跨域读取的资源的加载,那么这些想读取的资源究竟是根本就没有发送还是已经发送了却被浏览器给禁止加载了呢?
可以很明显的看出,已经接收了所请求的资源,但因为不同源被浏览器拦截了。
CORS是什么?
随着时代的发展,技术的进步,新的需求逐渐产生。人们开始有了跨域请求资源的需要,同源策略这样一股脑的禁止所有的跨域请求显然不合适,但放弃同源策略更是不可能的,允许不同源的页面相互作用是一场灾难。在这样的需求与矛盾下,CORS应运而生。
跨域资源共享(Cross-origin resource sharing),简称CORS,它使某些页面可以跨域请求来自特定的不同源的页面资源。
CORS依托于浏览器,如果浏览器不支持CORS,那么便无法使用,不过现在几乎没有不支持CORS的浏览器。
当发出跨域请求时,浏览器会在请求报文头中加入字段 Origin:xxx 来说明发起跨域请求的源,当另一端的服务器接受到了带有Origin的请求时,它会将所请求的资源放入响应报文中返回,并在响应头中加入一些以 Access-Control- 开头的字段,我们需要关注的只有其中两个:
- Access-Control-Allow-Origin: 它的值只能是一个外域的URI或者是*(只能有一个URI或*,不能写像 Access-Control-Allow-Origin:http://a.com,http://b.com 这样的,虽然这样很方便,但它是不被允许的,该字段后只允许有唯一一个URI,下文会说一种设置多个允许跨站的域的方法),这个值是允许进行跨域请求的源,浏览器接收响应后先比对这个字段中的URI是不是发起请求的Origin,若为*则允许所有域名的请求。如果两者一样,则允许这次跨域请求,响应中的所请求的资源将会被加载到浏览器上。
- Access-Control-Allow-Credentials: 这个字段的值只能是true,则接收的数据中包含cookie,若不设置该字段,则不发送cookie。
如此,通过CORS,可以实现几个特定的域之间的跨域的访问。
CORS设置:
修改一下hosts,模拟两个不同的站点:
192.168.10.103 www.test.com 192.168.10.103 www.hack.com
按照自己的情况修改ip,
如果跨站请求成功会显示success,
被请求的url,http://www.test.com/test/test.php
<?php
echo 'success'; ?>
发起跨域请求的url,http://www.hack.com/test/1.html
<!DOCTYPE> <html> <p>Hello<p> <script type="text/javascript"> function test() { var ajax = new XMLHttpRequest(); ajax.onreadystatechange=function() { if(ajax.readyState == 4 && ajax.status == 200) { var text = ajax.responseText; document.write(text) } } ajax.open("GET","http://www.test.com/test/test.php","true") ajax.send(); } test(); </script> </html>
在hack.com的页面上请求test.com的资源:
显示禁止跨域发出xmlhttprequest请求
<?php header('Access-Control-Allow-Origin:http://www.hack.com'); echo 'success'; ?>
加入Access-Control-Allow-Origin字段允许hack.com的源跨站请求资源。
跨站访问成功。
当我们把Access-Control-Allow-Origin改为http://www.a.com时:
又失败了。
漏洞的产生
漏洞产生的原因可分为两个,它们的原因都出在Access-Control-Allow-Origin上,当配置为星号*时,来自任何一个域名上的脚本都可以请求这个页面上的所有信息,相当于手动禁止了同源策略,这个原因的可能性极小,因为除非是一个全无经验的人,否则没有人会将其设置为*。另一个原因出现的几率就远远大于第一个了,其原因为由程序员的大意或疏忽导致匹配的不严谨。
不完全匹配:
这种问题是由于当按一定的规则来确认发起跨域请求的源是否应该允许访问时,匹配的规则有纰漏,只确认了其中某一部分符合规则就认为源一定是可信任的,例如:
将http://www.test.com/test/test.php进行更改
<?php $origin = $_SERVER['HTTP_ORIGIN']; $pattern = '#www.a.com#'; preg_match($pattern,$origin,$match); if ($match) { header('Access-Control-Allow-Origin:'.$origin); } echo 'success'; ?>
这段代码中,只要匹配到www.hack.com,并没有确认其他部分的内容就简单的判断允许跨域请求,当攻击者使用 www.a.com.hack.com 时,很容易就骗过了规则,成功发起跨域请求并接收。
再举个例子,当匹配规则为确认 a.com 在Origin末尾时才允许访问,显然上面一个例子中的方法不再适用,这时仍可以构造 bbbbbbba.com 这样的域名来突破限制。
道高一尺魔高一丈,匹配规则有很多,突破方法有更多,这里就不一一列举了。
没有转义:
当用正则表达式进行匹配时,URI中存在着许多点 . 像 bp.a.com , tieba.baidu.com , www.billbill.com 小数点.这个符号在正则表达式可以代替着任意一个字符,如果想让其仅仅代表.这个符号本身而不是匹配任何一个字符的话,应当使用转义符\. ,但很多人往往总会忘记转义,如在上述的代码中就没有进行转义:
http://www.test.com/test/test.php中注意:
$pattern = '#www.a.com#';
当我们使用 www.aacom.com , www.wwwaaacom.com , www.wwwaa.com 在 . 的位置随意写上一个字符就可以突破限制,正确写法应该是www\.a\.com
当头设置了Access-Control-Allow-Credentials:true时,恰巧产生了CORS漏洞,危害会大大增加,因为向其发起跨域请求时,它会将cookie一起发送,这是及其不希望看到的,也是非常危险的,读取了页面上的一些信息有时或许无伤大雅,但读取了cookie很多时候都是非常恐怖的。
漏洞检测与利用
CORS漏洞会加强xss的攻击力,哪怕是反射型的xss也增加了许多可能性。
检测CORS的方式可以通过不断修改Origin,检测响应中的Access-Control-Allow-Origin的值是否与Origin相同,如若相同,则存在CORS漏洞,github上有一个CORS漏洞的检测工具CORScanner,当检测到CORS时,可以这样利用:
<script> var ajax = new XMLHttpRequest(); ajax.open('GET','http://xxx','true'); ajax.onload = main; ajax.withCredentials = true; ajax.send() function main(){ xxx }
其中,ajax.withCredentials = true;这一段代码的作用是将Access-Control-Allow-Credentials:true设置为true以允许读取cookie,提升危害,main中写入可以读取敏感数据birucookie并将其发送给攻击者的代码,诱使受害者执行这段代码,就可以达到获取重要信息的目的。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
总体来说,CORS漏洞现在看来危害并不是特别大,但是千里之堤溃于蚁穴,无论怎样的漏洞都要有足够的重视,既是对自己负责,也是对他人负责、