本博客內容部分來自於
漏洞銀行
公開的學習視頻之中,感謝漏洞銀行的無償技術分享
。
第一部分:瀏覽器同源策略
學習跨域資源共享之前,首先要瞭解到的是
瀏覽器同源策略
這個概念。這樣便於後續的跨域資源共享漏洞的理解和運用。
同源策略(Same origin policy)
是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會受到影響。可以說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現。
– 摘自:百度百科
所謂同源是指,域名,協議,端口相同。
- 下面,以某個URL地址爲例,來直觀的瞭解同源策略。
其中:第一行和第二行均成功,是因爲這兩個URL相對於上面的URL來說只是不同的目錄和不同的文件,但是它們相對於上面的URL來說卻是`同一個域名,同樣的協議,同樣的端口.`
第二部分:兩種跨域的方法 1
- JSONP跨域請求
- CORS跨域請求
由於目前的很多項目都是前後端分離的,但是由於瀏覽器同源策略的緣故,因此就一定會出現跨域的問題,而處理跨域的方法有很多種類,上述只是兩種處理跨域的方式。而處理跨域也就意味着可能會出現
-跨域資源共享(CORS)漏洞
.
2.1 JSONP跨域的處理方式
JSONP其實已經落後了,因爲通過JSONP來處理跨域的話,只能處理get請求,其他的請求方式根本無法實現。這裏不做重點闡述
2.2 CORS跨域的處理方式
CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)。它允許瀏覽器向跨源(協議 + 域名 + 端口)服務器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。
CORS 需要瀏覽器和服務器同時支持。目前,所有瀏覽器都支持該功能,IE 瀏覽器不能低於 IE10。
CORS 背後的基本思想,就是使用自定義的 HTTP 頭部讓瀏覽器與服務器進行溝通,從而決定請求或響應是應該成功,還是應該失敗。
整個 CORS 通信過程,都是瀏覽器自動完成,不需要用戶參與。對於開發者來說,CORS 通信與同源的 AJAX 通信沒有差別,代碼完全一樣。瀏覽器一旦發現 AJAX 請求跨源,就會自動添加一些附加的頭信息,有時還會多出一次附加的請求,但用戶不會有感覺。
因此,實現 CORS 通信的關鍵是服務器。只要服務器實現了 CORS 接口,就可以跨源通信。
2.2.1 瀏覽器將CORS請求分成兩類:
- 簡單請求(simple request)
- 非簡單請求(not-so-simple request)。
只要同時滿足以下兩大條件,就屬於簡單請求
。
一、 請求方法是以下三種方法之一:
HEAD
GET
POST
二、HTTP的頭信息不超出以下幾種字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限於三個值 application/x-www-form-urlencoded、multipart/form-data、text/plain
凡是不同時滿足上面兩個條件,就屬於非簡單請求。
而瀏覽器對這兩種請求的處理,是不一樣的。
簡單請求
- 在請求中需要附加一個額外的 Origin 頭部,其中包含請求頁面的源信息(協議、域名和端口),以便服務器根據這個頭部信息來決定是否給予響應。例如:Origin: http://www.tomatocc.cn
- 如果服務器認爲這個請求可以接受,就會在 Access-Control-Allow-Origin 頭部中回發相同的源信息(如果是公共資源,可以回發 * )。例如:Access-Control-Allow-Origin:http://www.tomatocc.cn
- 沒有這個頭部或者有這個頭部但源信息不匹配,瀏覽器就會駁回請求。正常情況下,瀏覽器會處理請求。
注意,請求和響應都不包含 cookie 信息。
- 如果需要包含 cookie 信息,ajax 請求需要設置 xhr 的屬性 withCredentials 爲 true,服務器需要設置響應頭部 Access-Control-Allow-Credentials: true。
非簡單請求
瀏覽器在發送真正的請求之前,會先發送一個 Preflight 請求給服務器,這種請求使用 OPTIONS 方法,發送下列頭部:
- Origin:與簡單的請求相同。
- Access-Control-Request-Method: 請求自身使用的方法。
- Access-Control-Request-Headers: (可選)自定義的頭部信息,多個頭部以逗號分隔。
第三部分:跨域資源共享(CORS)漏洞
上面知道了處理跨域的時候可以通過CORS來處理跨域,但是,如果你的Access-Control-Allow-Origin是可控的(本人理解爲如果在response組裝的時候將Access-Control-Allow-Origin的值直接從請求中獲取,並不是指定某些ip和端口,那麼便存在可控。),且Access-Control-Allow-Credentials爲true(允許cookie跨域),那麼就可以利用一個可控的網站來竊取一個人的個人隱私信息。
下面通過一副圖片來看一下利用跨域資源共享(CORS)漏洞來獲取站點信息的原理
該圖的盜取過程基本是如下幾個步驟:
1.用戶登陸了一個存在跨域的網站,並且這個網站的跨域處理方式爲CORS,並且開發人員處理跨域的時候滿足cookie跨域和Origin是可控的。那麼用戶在登陸之後這個網站後,網站便會將一些cookie信息保存在瀏覽器中。
2. 這個時候我們向該用戶發送一個釣魚網站,用戶點開這個釣魚網站之後,釣魚網站會向服務器發送一個Ajax異步請求,然後將返回的響應發送給攻擊者。
3.1 CORS漏洞與CSRF漏洞對比
相同點:
- 都要藉助第三方網站
- 都要藉助ajax的異步過程
- 一般都需要用戶登陸
不同點:
- 第三方網站可以利用CORS漏洞讀取到受害者的敏感信息
- 第三方網站可以利用csrf漏洞可以替受害者完成諸如轉賬等敏感操作
- 一般有CORS漏洞的地方都有csrf漏洞
實戰演示:
1) 使用burp來尋找一些可能存在CORS漏洞的站點。
我們將所有的請求頭統一增加一個Origin參數,來滿足跨域
2) 在HTTP History中做一些過濾處理
3)然後我們去訪問一些網站,這樣就可以看出來哪些網站是存在CORS漏洞。
3.2 "null"源問題
從上面的文章中可以知道,處理跨域到時候如果Origin可控,則會出現CORS漏洞,那麼如果攻擊者在發送請求的時候將Origin的值設置爲
null
會發生什麼?
下圖摘自 漏洞銀行
CORS的規範中特意的提到了“NULL”源的概念,觸發這個源是爲了頁面跳轉或者是來自本地HTML文件。
目標應用可能會接收“null”源,並且這個可能被測試者(或者攻擊者)利用,任何網站很容易使用沙盒iframe來獲取“null 源”
第四部分:跨域資源共享(CORS)漏洞防禦
上面講解了CORS的漏洞原理和利用方式,那麼該介紹怎麼防護了。
實戰代碼:(存在CORS漏洞)
下方代碼是我處理跨域問題的方式。
package com.demo.invocation;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import com.jfinal.core.Controller;
import com.jfinal.log.Log;
public class AjaxInterceptor implements Interceptor {
private static Log log = Log.getLog(AjaxInterceptor.class);
public void intercept(Invocation inv) {
Controller controler = inv.getController();
/** 不安全的方案**/
// 獲得請求頭信息
HttpServletRequest req = controler.getRequest();
// 獲取請求頭的 Origin 參數
String origin = req.getHeader("Origin");
// 獲取請求頭的 Access-Control-Allow-Headers參數
//String headers= req.getHeader("Access-Control-Allow-Headers");
// 獲得響應信息
HttpServletResponse res = controler.getResponse();
//**組裝響應頭**//*
//客戶端地址
res.addHeader("Access-Control-Allow-Origin", origin);// *號不能滿需帶cookie的跨域請求
// 設置響應頭q
//res.addHeader("Access-Control-Allow-Headers", headers);
// 設置響應方法 允許所有方法進行跨域訪問
res.addHeader("Access-Control-Allow-Methods", "*");
//設置響應預檢命令的緩存時間(設置後,瀏覽器在該時間內只會預檢一次) 單位秒
//res.addHeader("Access-Control-Max-Age", "3600");
// cookie跨域的問題 請求頭解決方式
res.addHeader("Access-Control-Allow-Credentials", "true");
/** 下面爲解決方案**/
/* // 獲得響應信息
HttpServletResponse res = controler.getResponse();
res.addHeader("Access-Control-Allow-Origin", "http://127.0.0.1:8082");// *號不能滿需帶cookie的跨域請求
res.addHeader("Access-Control-Allow-Methods", "GET");
//要儘可能的返回"Vary: Origin"這個頭部,以避免攻擊者利用瀏覽器緩存
res.addHeader("Vary", "Origin");*/
inv.invoke();
}
}
圖中紅色方框的代碼就明顯滿足CORS漏洞的產生,當然我是用漏掃工具也掃出來了這個問題。
漏掃結果:報出了CORS漏洞
並且之前的過濾也成功實現(存在CORS漏洞)
後面,我將不安全的方案註釋掉,使用安全的方案,可以看到已經不存在漏洞了。
防禦方案:
- 不要配置"Access-Control-Allow-Origin" 爲通配符 “*” ,而且更爲重要的是,要嚴格效驗來自請求數據包中的“Origin”的值。當收到跨域請求的時候,要檢查“Origin” 的值是否是一個可信的源,還要檢查是否爲null。
- 避免使用 “Access-Control-Allow-Credentials :true” (請求中帶cookie)
- 減少“Access-Control-Allow-Methods”所允許的方法(只需要配置你所需要的即可)
個人總結
1)如果響應的Access-Control-Allow-Origin值是從request中的Origin參數中獲取的話,那麼就會存在CORS漏洞。即下列代碼
HttpServletRequest req = controler.getRequest();
// 獲取請求頭的 Origin 參數
String origin = req.getHeader("Origin");
HttpServletRequest req = controler.getRequest();
res.addHeader("Access-Control-Allow-Origin", origin)
2)如果響應的Access-Control-Allow-Origin值是 * 號,Access-Control-Allow-Credentials值爲true的話,那麼也不存在
CORS漏洞。
HttpServletResponse res = controler.getResponse();
//**組裝響應頭**//*
res.addHeader("Access-Control-Allow-Origin", "*");
res.addHeader("Access-Control-Allow-Credentials", "true");
3) 但是從最安全的角度來講,使用上面的建議來預防CORS漏洞是更爲安全的。
下面爲我的真實解決方案:
// 獲得請求頭信息
HttpServletRequest req = controler.getRequest();
// 判斷是否爲null源漏洞
String origin = req.getHeader("Origin");
if(origin.equals("null")) {
System.out.println("null 源漏洞 處理異常");
} else {
// 獲得響應信息
HttpServletResponse res = controler.getResponse();
res.addHeader("Access-Control-Allow-Origin", "http://127.0.0.1:8082");// 指定可信的源
res.addHeader("Access-Control-Allow-Methods", "GET");
//要儘可能的返回"Vary: Origin"這個頭部,以避免攻擊者利用瀏覽器緩存
res.addHeader("Vary", "Origin");
inv.invoke();
}
參考資料:
【網絡安全學習】系列教程
《網絡安全學習》第一部分-----初識OWASP
《網絡安全學習》第二部分-----SQL注入學習
《網絡安全學習》第三部分-----XSS攻擊系列學習
《網絡安全學習》第四部分-----SSRF服務器端請求僞造
《網絡安全學習》第五部分-----遠程代碼執行漏洞
《網絡安全學習》 第六部分-----文件上傳漏洞
《網絡安全學習》 第七部分-----跨域資源共享(CORS)漏洞
關於跨域
原理,及相關處理方案可以參考我的另一篇博客
《實戰開發》AJAX跨域問題處理 ↩︎