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漏洞利用問題
