Stories

Detail Return Return

一文深入瞭解CSRF漏洞 - Stories Detail

1.1. 定義

跨站請求偽造(英語:Cross-site request forgery),也被稱為 one-click attack 或者 session riding,通常縮寫為 CSRF 或者 XSRF, 是一種挾制用户在當前已登錄的Web應用程序上執行非本意的操作的攻擊方法。跟跨站腳本(XSS)相比,XSS 利用的是用户對指定網站的信任,CSRF 利用的是網站對用户網頁瀏覽器的信任。

跨站請求偽造攻擊,是攻擊者通過一些技術手段欺騙用户的瀏覽器去訪問一個用户自己曾經認證過的網站並執行一些操作(如發郵件,發消息,甚至財產操作如轉賬和購買商品)。由於瀏覽器曾經認證過,所以被訪問的網站會認為是真正的用户操作而去執行。這利用了web中用户身份驗證的一個漏洞:簡單的身份驗證只能保證請求是發自某個用户的瀏覽器,卻不能保證請求本身是用户自願發出的

Note

簡單來説就是你點擊我構造的惡意鏈接,我就可以以你的名義去發起一個http請求

1.2. 舉例

  1. 假如X銀行用以執行轉賬操作的URL地址如下

     https://bank.example.com/withdraw?amount=1000&to=PayeeName
  2. 一個惡意攻擊者在另一個網站中https://evil.com/中放置如下代碼

     <img src="https://bank.example.com/withdraw?amount=1000&to=Bob" />
  3. 如果有登陸了X銀行的用户訪問惡意站點https://evil.com/,那麼就會攜帶cookie去請求對應的轉賬URL,向Bob轉賬1000元

Note

這種惡意的網址可以有很多種形式,藏身於網頁中的許多地方,只要能讓受害者發起對應的請求即可,如上述中的轉賬請求。

攻擊者也不需要控制放置惡意代碼的網站,例如他可以將這種地址藏在各大論壇,博客等任何用户生成內容的網站中,這意味着如果服務端沒有合適的防禦措施的話,用户即使訪問熟悉的可信網站也有受攻擊的危險

通過例子也能夠看出,攻擊者並不能通過CSRF攻擊來直接獲取用户的賬户控制權,也不能直接竊取用户的任何信息。他們能做到的,是欺騙用户的瀏覽器,讓其以用户的名義執行操作

1.3. 攻擊流程

image.png

具體的攻擊流程如下:

  1. 用户正常登錄web服務,並一直保持在線
  2. 服務器返回用户憑證Session ,並將其保存在Cookie中
  3. 攻擊者生成payload,並放置在用户可訪問的地方
  4. 攻擊者誘導用户點擊在第3步放置的鏈接,此時用户一直在線,且是用同一瀏覽器打開(保證Cookie未失效)
  5. 用户點擊惡意鏈接
  6. 惡意鏈接向服務器請求,由於用户Cookie未失效,就攜帶用户Cookie訪問服務器
  7. 服務器收到請求,此時用户Cookie 未失效,並判定為“用户”發起的正常請求,並做出響應

1.4. 分類

1.4.1. GET型

這種是最容易利用的,相比於POST型來説,攻擊面也大很多,比如上述CSRF轉賬例子中就是GET型的

在web應用中,很多接口通過GET進行數據的請求和存儲,如果未對來源進行校驗,並且沒有token保護,攻擊者可以直接通過發送含有payload的鏈接進行誘導點擊;亦可以通過評論區或類似功能處發佈圖片,通過修改img地址的方式保存至頁面,用户訪問便會進行自動加載造成攻擊

<!-- 不論什麼手段,只要能讓受害者訪問一個鏈接即可 -->
<img src="https://bank.example.com/withdraw?amount=1000&to=Bob" />

1.4.2. POST-表單型

相比於GET型,這種就要多很多,因為很多開發在提交數據的功能點時都會採用POST,如創建用户、創建文章、發消息等,利用起來也相對麻煩點

Note

測試時,為了擴大危害,可以嘗試將POST數據包轉換成GET數據包,後端採用如@RequestMaping("/")這種同時接受POST和GET請求的話,就可以成功

利用起來無非也是構造一個自動提交的表單,然後嵌入到頁面中,誘導受害者訪問,受害者訪問後會自動提交表單發起請求

<form action=http://bank.example.com/csrf method=POST>
<input type="text" name="amount" value="1000" />
</form>
<script> document.forms[0].submit(); </script>

1.4.3. POST-JSON型

現在越來越多的系統都採用RESTful風格開發,前後端分離,ajax請求後端獲取數據再到前端渲染,所以上述表單型也越來越少了

如果我們發現請求頭中的Content-Type值是application/json,基本上就可以確定採用了前後端分離了

image-20220107104042244

這種一般有4⃣️種利用手法:

  1. json轉param
  2. 閉合JSON
  3. ajax發起請求
  4. flash+307跳轉

json轉param

部分網站可能同時支持json和表單格式,所以我們可以嘗試進行轉換,也算是一個小tips吧

如把 {"a":"b"} 轉換為 a=b,服務端可能也會解析


閉合JSON

這種要求對Content-Type沒有限制,比如傳輸的數據為 {"a":"b"},那麼我們就可以構造一個表單

<form action=http://test.example.com/csrf method=POST>
    <!-- 重點是下面這一行 -->
    <input type="hidden" name='{"a":"' value='b"}' />
</form>
<script> document.forms[0].submit(); </script>

這樣自動提交表單的時候,提交的data就是 {"a":"=b"},閉合成了json

Note

實際環境中本人沒遇到過,基本上遇到的都是強制要求Content-Type為json


ajax發起請求

  • XMLHttpRequest跨域預檢

當跨域影響用户數據HTTP請求(如用XMLHttpRequest發送get/post)時,瀏覽器會發送預檢請求(OPTIONS請求)給服務端徵求支持的請求方法,然後根據服務端響應允許才發送真正的請求。

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Access-Control-Allow-Origin: http://localhost:63342
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1800
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: content-type,access-control-request-headers,access-control-request-method,accept,origin,x-requested-with
Content-Length: 0
Date: Wed, 11 Mar 2015 05:16:31 GMT

然而如果服務端對Content-Type進行校驗,則不會響應這個OPTIONS請求,從而利用失敗。但是更多的情況下服務端可能不會校驗Content-Type,或者不會嚴格校驗Content-Type是否為application/json,所以很多情況下這是可用的

<script>
  windows.onload = () => {
    var xhr = new XMLHttpRequest()
    xhr.open("POST", "http://test.example.com/csrf")
    xhr.setRequestHeader("Accept", "*/*")
    xhr.setRequestHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3")
    xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8")
    xhr.withCredentials = true // 攜帶cookie
    xhr.send(JSON.stringify({"a":"b"})
  }
</script>

flash+307跳轉

利用Flash的跨域與307跳轉來繞過http自定義頭限制,307跟其他3XX HTTP狀態碼之間的區別就在於,HTTP 307可以確保重定向請求發送之後,請求方法和請求主體不會發生任何改變。HTTP 307會將POST body和HTTP頭重定向到我們所指定的最終URL,並完成攻擊

詳情參考該系列我的另一片文章:一次XSS和CSRF的組合拳進攻(CSRF+JSON)

1.5. 挖掘

算是一些挖掘經驗吧,很多小夥伴都知道這個漏洞,但是不知道如何挖掘。

1.5.1. 應用場景

其實所有需要登陸認證且存在操作的地方,都可能存在CSRF;比如修改個人信息、發送郵件、創建管理員用户等等,只能查看的功能不考慮,因為不能算真正利用

1.5.2. 如何快速驗證

Tip

觀察數據包,如果header頭和data中都沒有token,然後嘗試刪除referer,還是能成功發送請求的話,就可以確定存在CSRF漏洞了

為了保險起見,在時間充足的情況下,還是需要儘量通過POC驗證下,一般不需要2個賬號進行驗證,一個賬號即可(2個只能説更保險)

非json的情況下,使用burp可以快速生成POC,也可以自己寫,反正原理都是發起請求即可

登陸賬號的情況下去訪問這個poc,如果能成功得到自己的結果,就是OK的。

image-20220107112455842

1.6. 防禦

WEB的身份驗證機制可以保證一個請求是來自於哪個用户的瀏覽器,但是卻不能保證請求是否由本人發起的,所以修復和防禦也是保證請求由用户本人發起即可。

Tip

簡單來説,或者和客户溝通的情況下,直接説修復方法就是防止請求重放,他們開發也差不多都知道怎麼修了

1.6.1. 令牌同步模式

令牌同步模式(英語:Synchronizer token pattern,簡稱STP)。

原理是:當用户發送請求時,服務器端應用將令牌(token:一個保密且唯一的值)嵌入HTML表格,併發送給客户端。客户端提交HTML表格時候,會將令牌發送到服務端,再由服務端對令牌進行驗證。令牌可以通過任何方式生成,只要確保隨機性和唯一性。這樣確保攻擊者發送請求時候,由於沒有該令牌而無法通過驗證。(沒有token不能重放數據包)

<input type="hidden" name="_csrf_token" value="YidlXHhlMVx4YmJceDkxQFx4OTdceDg5a1x4OTJcbic=">

Note

STP能在HTML下運作順利,但會導致服務端的複雜度升高,複雜度源於令牌的生成和驗證。因為令牌是唯一且隨機,如果每個表格都使用一個唯一的令牌,那麼當頁面過多時,服務器由於生產令牌而導致的負擔也會增加。而使用會話(session)等級的令牌代替的話,服務器的負擔將沒有那麼重。

1.6.2. 檢查Referer字段

HTTP頭中有一個Referer字段,這個字段用以標明請求來源於哪個地址。在處理敏感數據請求時,通常來説,Referer字段應和請求的地址位於同一域名下

以上文銀行操作為例,Referer字段地址通常應該是轉賬按鈕所在的網頁地址,應該也位於bank.example.com之下。而如果是CSRF攻擊傳來的請求,Referer字段會是包含惡意網址的地址,不會位於bank.example.com之下,這時候服務器就能識別出惡意的訪問。

image-20220107100706077

Warning

這種辦法簡單易行,工作量低,僅需要在關鍵訪問處增加一步校驗。

但這種辦法也有其侷限性,因其完全依賴瀏覽器發送正確的Referer字段;雖然http協議對此字段的內容有明確的規定,但並無法保證來訪的瀏覽器的具體實現,亦無法保證瀏覽器沒有安全漏洞影響到此字段,並且也存在攻擊者攻擊某些瀏覽器,篡改其Referer字段的可能。

1.6.3. 添加校驗token

Note

提交不一定是在data裏面提交,也可以在header裏面

由於CSRF的本質在於攻擊者欺騙用户去訪問自己設置的地址,所以如果要求在訪問敏感數據請求時,要求用户瀏覽器提供不保存在cookie中,並且攻擊者無法偽造的數據作為校驗,那麼攻擊者就無法再執行CSRF攻擊。

這種數據通常是窗體中的一個數據項。服務器將其生成並附加在窗體中,其內容是一個偽隨機數。當客户端通過窗體提交請求時,這個偽隨機數也一併提交上去以供校驗。正常的訪問時,客户端瀏覽器能夠正確得到並傳回這個偽隨機數,而通過CSRF傳來的欺騙性攻擊中,攻擊者無從事先得知這個偽隨機數的值,服務端就會因為校驗token的值為空或者錯誤,拒絕這個可疑請求。

1.6.4. 一次一用驗證碼

在關鍵操作處添加一次一用的驗證碼,攻擊者無法事先知道驗證碼的值,也就無法成功構造發起請求的數據包。

Attention

需要用户交互,如果很多地方都加上,用户體驗極差,所以一般不建議這個

1.6.5. 使用SameSite Cookie

設置SameSite屬性,需要根據需要設置

  1. 如果Samesite Cookie被設置為Strict,瀏覽器在任何跨域請求中都不會攜帶Cookie,新標籤重新打開也不攜帶,所以説CSRF攻擊基本沒有機會;但是跳轉子域名或者是新標籤重新打開剛登陸的網站,之前的Cookie都不會存在。尤其是有登錄的網站,那麼我們新打開一個標籤進入,或者跳轉到子域名的網站,都需要重新登錄。對於用户來講,可能體驗不會很好。
  2. 如果Samesite Cookie被設置為Lax,那麼其他網站通過頁面跳轉過來的時候可以使用Cookie,可以保障外域連接打開頁面時用户的登錄狀態。但相應的,其安全性也比較低。

圖片

1.7. 個人預防

網站如果存在CSRF漏洞,個人一般要如何操作才能防止攻擊到自己呢?

  1. 儘量每次使用隱私瀏覽器,因為其關閉後會清空所有的cookie
  2. 不要隨便打開鏈接,一定要打開的情況下,可以使用隱私瀏覽器

Add a new Comments

Some HTML is okay.