跨站資源共享(CORS)漏洞的誤配置及檢測方法


 

基本知識

同源策略(Same Origin Policy, SOP)

同源策略是瀏覽器級別的安全機制。 它的核心觀點是,來自不同源(域名、 端口或者協議有一項不同都算)的Web應用不共享任何資源。

例如,在父頁面中建立一個iframe標簽指向另一個域名,父頁面和iframe屬於不同源,不能相互讀取DOM樹。 父頁面只能控制iframe發送get或post請求,卻不能讀取請求的內容。 但有時候,我們需要在不同域的web應用之間交換數據,這時候有以下幾種常用的跨域方法:JSONP,window.postMessage(),CORS。

 

跨域資源共享(Cross-Origin Resource Sharing, CORS)

CORS的原理是,當我們要進行跨域請求時,在服務端的響應頭中加入相應header,通知瀏覽器添加特例放寬同源策略的限制。 重要的響應頭有:

 

- Access-Control-Allow-Origin: http://a.com  服務端接受來自http://a.com的跨域請求

- Access-Control-Allow-Credentials: true  表示是否允許發送Cookie,true即發送cookie

 

 

 

如果a.com要和b.com通信,且b.com可以用如下代碼開啟CORS響應頭:

 

<?php
header("Access-Control-Allow-Origin: http://a.com");
header("Access-Control-Allow-Credentials: true");
?>

 

而a.com可以使用下面的js代碼與b.com通信,讀取b.com的內容:

 

var xhr=new XMLHttpRequest();
xhr.onreadystatechange = function() {
    if (xhr.readyState == XMLHttpRequest.DONE) {
        alert(xhr.responseText);
    }
}
xhr.open(“GET“, ”http://b.com/api“, true);
xhr.withCredentials = true;
xhr.send();

 

 

CORS誤配置及檢測方法

檢測CORS配置錯誤相對比較簡單,因為大部分服務器都是使用請求包的Origin頭進行控制的,而我們可以任意修改Origin頭。 只要對比響應頭中ACAO和ACAC的變化,便可以判斷是否存在漏洞。 基本腳本如下:

 

import requests

acao = ''
acac = ''

headers = {'Origin': 'test'}
r = requests.get('http://192.168.140.129/cors/1.php', headers=headers)

if 'Access-Control-Allow-Origin' in r.headers:
    acao = r.headers['Access-Control-Allow-Origin']
if 'Access-Control-Allow-Credentials' in r.headers:
    acac = r.headers['Access-Control-Allow-Credentials']

print("Access-Control-Allow-Origin: " + acao)
print("Access-Control-Allow-Credentials: " + acac)

 

 

反射Origin頭

為了安全考慮,ACAO頭默認不允許填寫多個域名。 有些開發者為了方便,直接在Access-Control-Allow-Origin中反射請求的Origin值。作為ACAO的域名,這樣使得所有人都可以輕易訪問該域名內容,竊取隱私數據。

服務端代碼為:

<?php
header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
header("Access-Control-Allow-Credentials: true");
?>

 

錯誤 Nginx 配置示例:

 

add_header "Access-Control-Allow-Origin" $http_origin;
add_header “Access-Control-Allow-Credentials” “true”;

 

這種配置非常危險,相當於信任任意網站,給攻擊者網站敞開了大門。任意攻擊者網站可以直接跨域讀取其資源內容。

 

檢測方法:

使用不同Origin頭請求同一個服務器,查看響應頭中Access-Control-Allow-Origin是否總是與Origin相同。

 

Origin校驗錯誤

有些Origin檢測的方法比較寬松,造成只匹配了前綴、 后綴、 沒有轉義”.”等情況。

 

檢測方法:

先發送一個請求,得到CORS頭后,在其中加入前綴、 后綴以及將”.”替換成任意字符,查看響應頭是否同步變化

 

信任null

有些web應用為了與本地file頁面共享數據,將ACAO頭設置為Null,但攻擊者可以使用如下代碼發送Origin為Null的請求。

 

<iframe sandbox="allow-scripts allow-top-navigation allow-forms" src='data:text/html,<script>var xhr=new XMLHttpRequest();

xhr.onreadystatechange = function() {

if (xhr.readyState == XMLHttpRequest.DONE) {

        alert(xhr.responseText);

    }

}

xhr.open("GET", "http://45.32.105.30:8080", true);

xhr.withCredentials = true;

xhr.send();</script>'></iframe>

 

檢測方法:

直接檢測返回頭CORS是否是NULL即可

 

HTTPS域信任HTTP域

如果https域的應用信任非http域,那么攻擊者可以先劫持受信任的http域,然后通過這個域發送跨域請求到https站,從而盜取信息。

 

檢測方法:

直接檢測https站點返回頭CORS是否信任http即可

 

信任自身任意子域

有些應用過分信用自身子域,當子域中發生XSS時,會放大XSS的危害。

 

檢測方法:

在請求Origin中發送目標站點的子域名,檢查返回頭ACAO

 

Origin: *與 Credentials: true 共用

如果是開放的公共資源,origin才會設置成通配符”*”,這種資源不應該允許攜帶cookie等訪問。

瀏覽器會對下面這種誤配置報錯:

Access-Control-Allow-Origin:*
Access-Control-Allow-Credentials:true

 

這就意味着,Access-Control-Allow-Origin:*只能用於共享公開資源。

 

檢測方法:

直接檢查目標返回頭即可。

 

缺少Vary: Origin頭

如果一個資源享有多個域名,它需要對不同域名的請求包生成不同的ACAO頭。 如果一個請求的響應被緩存,且返回中沒有Vary: Origin字段,可能會導致其它域名的請求失效。

 

檢測方法:

無法檢測,因為我們不知道一個服務器是否共享多個域名。

 

 

CORS漏洞掃描工具

https://github.com/chenjj/CORScanner

 

 

CORS安全配置最佳實踐

 

1. 不要盲目反射 Origin頭

2. 嚴格校驗 Origin 頭,避免出現權限泄露

3. 不要配置 Access-Control-Allow-Origin: null

4. HTTPS 網站不要信任HTTP 域

5. 不要信任全部自身子域,減少攻擊面

6. 不要配置 Origin:*和 Credentials: true

7. 增加 Vary: Origin 頭

 

 

參考鏈接:

https://eviloh.github.io/2018/08/06/CORS%E9%85%8D%E7%BD%AE%E9%94%99%E8%AF%AF%E6%A3%80%E6%B5%8B%E6%96%B9%E6%B3%95/

 


免責聲明!

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



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