CSRF跨站請求僞造原理以及防禦

打V最近重新溫習了一遍CSRF,決定寫個博客簡單記錄一下CSRF的原理,方便以後複習之用。

CSRF

CSRF的全稱爲 Cross-site request forgery,中文稱爲跨站請求僞造。顧名思義就是其他非法網站向合法網站發送被僞造的用戶請求。

經典場景

CSRF的其中一個經典場景就是銀行網銀轉賬。

  1. 用戶Bob登錄了網銀,並轉了100元給朋友,轉賬完成之後Bob並沒有點擊登出網銀

網銀系統發送瞭如下的請求。

POST /transfer HTTP/1.1
Host: bank.example.com
Cookie: JSESSIONID=randomid; Domain=bank.example.com; Secure; HttpOnly
Content-Type: application/x-www-form-urlencoded

amount=100&account={friend_account}

從中我們可以看到該請求包含了轉賬金額,以及接受轉賬的賬戶是朋友的賬戶 friend_account。

特別值得注意的是,該網銀系統是通過Cookie來驗證用戶的身份的。

  1. 用戶Bob無意間點進了攻擊者的網站,網站中隱藏的JavaScript也向網銀系統發送了一模一樣的請求,只不過收款賬戶變成了攻擊者的賬戶了
POST /transfer HTTP/1.1
Host: bank.example.com
Cookie: JSESSIONID=randomid; Domain=bank.example.com; Secure; HttpOnly
Content-Type: application/x-www-form-urlencoded

amount=100&account={attacker_account} // 篡改爲了攻擊者賬戶

於是,在神不知鬼不覺的情況下,Bob就這麼莫名其妙地給攻擊者打款了100元。

爲什麼會發生這種事情?

CSRF的攻擊之所以能夠成立,需要具備以下幾個關鍵因素:

  1. 網站使用Cookie驗證用戶
  2. 用戶沒有登出網站
  3. 網站沒有做任何CSRF的防禦

如果網站是使用Cookie在對用戶進行驗證的話,會產生一個問題。那就是隻要該請求是發往該網站的,無論是從哪裏發出的,瀏覽器都會自動捎帶目標網站的Cookie。因此當攻擊者僞造了用戶請求發向網銀系統時,該僞造的請求也會攜帶着合法的Cookies信息。只要用戶不主動登出網站,用戶瀏覽器裏的Cookies都會一直保存着登錄信息,並被攻擊者利用。

雖然攻擊者並沒有辦法查看用戶Cookie裏的信息,但是只要能把Cookies發出去就行了呀!

該如何防禦CSRF?

歸根結底,CSRF之所以能成功,是因爲服務器沒有辦法分辨哪個請求是合法的,而哪個請求又是攻擊者發出的。因爲他們長得都一樣。

那麼我們是否可以想一個辦法,讓合法的請求帶有一些特殊的信息,而且這特殊的信息是攻擊者所無法獲得的呢?

其中一個辦法就是加入 CSRF Token。

我們可以讓服務端針對用戶生成一個獨一無二的token,並將CSRF token放在我們自己的合法網站中。如果用戶是在我們的合法網站裏發送請求的話,就會夾帶CSRF token一起發出。接着,我們只需要在服務端驗證一下這個CSRF token就可以知道該請求是否合法了。

而攻擊者是無法獲取這個CSRF token的,因爲首先攻擊者必須以用戶的身份登錄我們的合法網站纔有辦法獲取該CSRF token,這就要求攻擊者必須獲得用戶的賬號密碼,或者是從中間截取用戶的合法請求,然而如此一來,這就變成了盜取賬號密碼以及中間人攻擊了,已經與CSRF無關了。CSRF的防禦只是僅僅針對CSRF攻擊本身而已

舉個例子,我們可以在提交列表中加入一個隱形的input,value就設定成我們的token,當用戶提交請求的時候,就會連這個CSRF token一起提交出去了。

<form action="https://bank.example.com/transfer" method="post">

  <input
      name="amount"
      value="100"
   />
      
  <input 
  	  type="hidden"
      name="token"
      value="{csrf_token}"
   />
      
  <input type="submit"/>
  
</form>

參考文檔:Spring Docs: Cross Site Request Forgery (CSRF)

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