CSRF漏洞跨域攜帶cookie問題
1. CSRF漏洞
用戶在登錄A網站www.a.com
,獲取會話憑證sessionid
,記錄在Cookie
中
此時用戶在同一窗口中打開新標簽頁網站Bwww.b.com
,網站B中含有惡意請求,請求內容為網站A中的接口
在用戶打開網站B后,瀏覽器會自動發起請求,這個時候會自動帶上A網站的Cookie
值
即在用戶無感的情況下,完成了一次以用戶身份對A網站的惡意請求
2. 什么情況下會發生CSRF
①用戶會話憑證存放在Cookie
中
②使用Cookie
中的會話憑證進行身份認證(有可能Cookie
中存放了sessionid
值,但是實際身份驗證是對Header
頭中的自定義字段Auth:sessionid
進行驗證)
③后端未校驗Referer
字段(Referer
字段記錄HTTP
請求源地址)
④后端允許跨域請求(非簡單請求,OPTIONS
請求預檢)
⑤使用GET請求進行重要操作(增刪改查)(http://www.a.com/creat.php?username=123&password=456)
(並非只有GET
請求會遭受攻擊,只是GET
請求較容易實現CSRF
攻擊)
3. CSRF的利用方式
①使用HTML
標簽發送正常跨域請求
②通過JS
發送請求(CORS
策略限制)
4. 實際滲透遇到問題
4.1 同源策略
同源策略是指兩個URL
的協議、域名、端口相同的話,那么這兩個URL為同源。
關於同源策略的官方說明
總的來說有以下三點限制:
1.無法讀取非同源網頁的 Cookie
、LocalStorage
和 IndexedDB
2.無法獲取非同源網頁的 DOM
3.向非同源地址發送 AJAX
請求瀏覽器會拒絕響應
4.2 跨域
根據CSRF攻擊的原理來講,攻擊者構造的惡意網站肯定是和要攻擊的網站是不同源的,所以這里要考慮的就是跨域的問題了,跨域的方法的話有兩種
4.2.1 JSONP跨域
JSONP利用了script
、iframe
等標簽的src
等屬性,這些屬性是沒有同源策略限制的,從而實現了跨域請求。
JSONP請求只能使用GET
方式發送請求,也就是說如果被攻擊的Web應用采用的是GET方式進行操作的話,可以使用JSONP進行CSRF
實現,但是在實際操作過程中需要考慮Cookie
問題,因為需要Cookie
中的字段進行身份驗證
對於JSONP跨域能否攜帶Cookie
的問題,理論上來說使用JSONP進行跨域是不能獲取Cookie
的,對於瀏覽器是否會攜帶跨域請求中對方域的Cookie
值,使用三種瀏覽器進行了測試
Firefox:攜帶網站A的Cookie值發起GET請求
Edge:沒有攜帶網站A的Cookie值發起GET請求
Chrome:沒有攜帶網站A的Cookie值發起GET請求
對於這個結果,和下面說到的CORS
的POST
跨域請求的結果是一樣的,應該都是因為SameSite
設置導致的。
4.2.2 CORS跨域
CORS將跨域請求分為兩種:簡單請求、非簡單請求
滿足下圖中所有限制的請求即為簡單請求,其余的均為非簡單請求
在滿足簡單請求的情況下,瀏覽器會自動攜帶Cookie
發送跨域請求,也就是說進行身份校驗的會話憑證如果存儲在Cookie
中,並且Web應用中的操作可以用簡單請求的方式完成,那么就一定存在CSRF
漏洞。
如果跨域請求為非簡單請求,則瀏覽器會先發送OPTIONS
預檢請求,后端服務器在接收到OPTIONS
請求后,會返回針對實際請求的要求,如果符合要求的話,則會繼續發送實際請求,如果不符合的話就不會發送實際請求了。
下圖為實際發送OPTIONS
請求,右側為后端服務器響應信息其中包含了對實際請求的要求
Access-Control-Request-Method
服務器允許客戶端使用POST
發起請求
Access-Control-Request-Headers
服務器允許請求中攜帶Content-Type
字段
Access-Control-Allow-Origin
服務器允許哪些域發起請求(由於上圖中的請求是本地文件目錄的HTML發起,如下圖所示,所以返回的是null)
Access-Control-Allow-Credentials
服務器是否允許使用憑證進行實際請求(例如攜帶Cookie)
如果實際請求都滿足了以上的要求,那么瀏覽器就會發送實際的請求,但是此時的話並未攜帶Cookie
值來完成CSRF
攻擊,如果想要實際請求攜帶Cookie
值的話,需要前后端滿足以下要求
后端:
①Access-Control-Allow-Credentials
字段設置為True
②Access-Control-Allow-Origin
字段不能設置為*
,必須為指定的域名,像上圖請求中的null也算是
前端:
①請求要設置withCredentials = true
在滿足上述前后端條件后,瀏覽器在完成預檢請求后會自動攜帶上Cookie字段,但是由於瀏覽器的內核特性不同,此時又出現了不同的情況
Firefox
攜帶網站A的Cookie值發起POST請求
Edge
沒有攜帶網站A的Cookie值發起POST請求
Chrome
沒有攜帶網站A的Cookie值發起POST請求
測試發現不同的瀏覽器在同樣的前后端配置下,對於Cookie
字段的攜帶產生了不同,於是又產生了以下內容:
查過資料后發現,Edge和Chrome使用的是同一內核,對於Cookie
中的SameSite
屬性默認是Lax
,在這種級別下,具有如下限制
在這種情況下,想要實現POST
跨域請求攜帶Cookie
在Chrome瀏覽器中是不行的
測試后發現在將Cookie中的某一字段SameSite
屬性值手動設置為None
(必須先設置字段的Secure
屬性,否則無效)時
發送POST
跨域請求時,Chrome(Edge)瀏覽器會自動攜帶上Cookie
中該字段值
這個就說明了在進行非簡單請求時,在滿足上文所講的前后端設置時,是否會自動攜帶Cookie
值在Chrome與Edge瀏覽器中取決於Cookie
的SameSite
字段的值,瀏覽器默認情況下設置為Lax
,如果要手動設置為None
的話,必須先設置Secure
屬性,否則無效。
本文僅從CSRF攻擊者視角出發,記錄一下實際滲透過程中遇到的CSRF漏洞利用問題