《網絡安全學習》 第七部分-----跨域資源共享(CORS)漏洞

本博客內容部分來自於漏洞銀行公開的學習視頻之中,感謝漏洞銀行的無償技術分享

第一部分:瀏覽器同源策略

學習跨域資源共享之前,首先要瞭解到的是瀏覽器同源策略這個概念。這樣便於後續的跨域資源共享漏洞的理解和運用。
同源策略(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

凡是不同時滿足上面兩個條件,就屬於非簡單請求。

而瀏覽器對這兩種請求的處理,是不一樣的。

簡單請求

  1. 在請求中需要附加一個額外的 Origin 頭部,其中包含請求頁面的源信息(協議、域名和端口),以便服務器根據這個頭部信息來決定是否給予響應。例如:Origin: http://www.tomatocc.cn
  2. 如果服務器認爲這個請求可以接受,就會在 Access-Control-Allow-Origin 頭部中回發相同的源信息(如果是公共資源,可以回發 * )。例如:Access-Control-Allow-Origin:http://www.tomatocc.cn
  3. 沒有這個頭部或者有這個頭部但源信息不匹配,瀏覽器就會駁回請求。正常情況下,瀏覽器會處理請求。注意,請求和響應都不包含 cookie 信息。
  4. 如果需要包含 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();
		}

參考資料:

W3C關於CORS規範

【網絡安全學習】系列教程

《網絡安全學習》第一部分-----初識OWASP
《網絡安全學習》第二部分-----SQL注入學習
《網絡安全學習》第三部分-----XSS攻擊系列學習
《網絡安全學習》第四部分-----SSRF服務器端請求僞造
《網絡安全學習》第五部分-----遠程代碼執行漏洞
《網絡安全學習》 第六部分-----文件上傳漏洞
《網絡安全學習》 第七部分-----跨域資源共享(CORS)漏洞


  1. 關於跨域
    原理,及相關處理方案可以參考我的另一篇博客
    《實戰開發》AJAX跨域問題處理 ↩︎

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章