什麼是CSRF??
大家都聽過一句話叫“陌生的連結不要亂點”,原因就是釣魚網站的連結點開之後會造成CSRF攻擊。 CSRF譯為“跨站請求偽造”。簡單來說就是釣魚網站連結盜用了使用者的資訊(例如銀行網站頒發給使用者的token),執行了非使用者本意的操作(如轉賬交易)。
舉個例子
a使用者是某bank的使用者,在a登入bank.com時,bank.com會設定響應頭
Set-Cookie: token=abcdefg;
以後a使用者再訪問bank.com時會在請求頭中自動攜帶該cookie。
這時a使用者點選了danger.com時,danger.com會響應一個頁面,頁面中可能包含以下元素
<img src="https://bank.com/pay?payuser=dangeruser&money=10000" />
雖然danger.com拿不到a使用者在bank.com的cookie,但<img/>
元素會向bank.com傳送請求,傳送請求就會攜帶cookie,而cookie中就包含使用者資訊(token),bank.com收到該請求,並驗證該使用者的token正確後,就會正常響應這個轉賬請求
<img/>
元素與ajax不同,不受到瀏覽器同源策略中跨域的影響,可以正常傳送請求
常見的CSRF攻擊防範手段
1.直接不使用cookie
不使用cookie行不行呢?肯定是可以,畢竟有localstorage嘛。但cookie的相容性比localstorage要好,很多大廠的網站依舊使用cookie。
並且cookie對ssr的場景較友好,因為服務端渲染中,構建頁面的地方在服務端。假設使用者已經登陸過a.com。那麼下次輸入url請求a.com時,自動攜帶cookie。a.com就能自動推薦該使用者喜歡的內容。而假設沒有使用cookie而是localstorage。使用者在請求a.com時,就不能自動攜帶localstorage中的使用者資訊,因為localstorage需要js來手動加到請求中。
2.使用SameSite
SameSite是近幾年新出的一個屬性,用於增強cookie的安全性,但相容性較差,用法如下。
Set-Cookie: token=abcdefg;SameSite=Lax;
SameSite有兩個取值
SameSite=Strict
這種設定下,瀏覽器只會在當前請求源和 cookie 設定的源相同時才傳送 cookie。即使使用者從別的站點點選了一個連結,跳轉到當前站點,cookie 也不會被髮送。
還是剛纔那個例子,由於使用者登入bank.com後bank.com響應的Set-Cookie中SameSite=Strict
Set-Cookie: token=abcdefg;SameSite=Strict;
即使danger.com中嵌入了
<img src="https://bank.com/pay?payuser=dangeruser&money=10000" />
由於 SameSite=Strict
的存在,danger.com與bank.com的源不一樣,cookie則不會攜帶過去。即使bank.com能收到轉賬請求,但由於沒有cookie中的token,則驗證失敗,拒絕轉賬請求。
它提供了最高階別的安全性,但也會影響到一些正當的跨站點請求。
SameSite=Lax
Lax譯為寬鬆的、不嚴格的。 當 SameSite=Lax 時,允許某些跨站點請求帶上 cookie,比如從其他站點透過 GET 請求連結到當前站點時會攜帶 cookie。然而,POST 請求、iframe、AJAX 等不會攜帶 cookie。
一般的轉賬請求都是使用POST
,<img/>
元素髮送的請求是GET
,則無法請求成功。
3.使用CSRF token
當用戶想轉賬時,在請求bank.com的轉賬頁面時,bank.com會響應一個CSRF token
Set-Cookie: CSRFtoken=qwerty;
這個CSRF token是一次性的,當用戶點選轉賬時,將CSRF token也一併提交。
bank.com比之前多加了一道驗證。不僅驗證a使用者的token,還要驗證使用者的CSRF token。驗證透過後,轉賬成功,CSRF token也自動失效。
總結
每種策略都有一定的隱患,因此在實際開發中,通常建議多種防護手段相結合,比如使用 CSRF Token 配合 SameSite Cookie 屬性,以達到更強的安全性。