什么是CSRF
Cross Site Request Forgery(跨站請求偽造),也被稱為 one-click attack 或者 session riding,通常縮寫為 CSRF 或者 XSRF, 是一種挾制用戶在當前已登錄的Web應用程序上執行非本意的操作的攻擊方法。
CSRF實例
- 用戶萌新登錄了銀行鏈接www.bank.com,萌新看見了www.bank.com上有個搶紅包按鈕,于是點擊
- hacker將搶紅包按鈕的代碼修改如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post" action="http://www.bank.com/transfer.php">
<input type="hidden" name="from" value="mengxin">
<input type="hidden" name="money" value="10000">
<input type="hidden" name="to" value="hacker">
<input type="button" onclick="submit()" value="搶紅包">
</form>
</body>
- 可以看到,實際上當萌新點了這個按鈕之后,執行的邏輯是從mengxin的賬戶里轉10000到hacker的賬上。
- 而此時,由于萌新剛訪問他的銀行后不久,他的瀏覽器與銀行網站之間的 session 尚未過期,瀏覽器的 cookie 之中含有萌新的認證信息,所以銀行認為發起這個請求的就是萌新本人,所以就轉賬成功,這個時候就GG了。
在這個例子中,由于瀏覽器的同源策略限制,實際上hacker并無法竊取到萌新的個人信息,而是直接利用了萌新未過期的個人信息直接偽造他的身份發起了轉賬請求。
如何防范
可以看到,CSRF對用戶來說很傷。那到底有什么辦法可以進行防范呢?目前常用的有兩種防范方法,下面一一講解。
一、HTTP referer字段驗證
在HTTP協議中,有這么一個字段叫referer,它記錄了網站請求的來源地址。比如上面的銀行轉賬例子,當萌新登錄www.bank.com后,點擊任何原網頁的鏈接和按鈕,請求來源都是www.bank.com。但當萌新點了被纂改后的鏈接或者按鈕后,他的來源地址變成了www.hacker.com。所以,銀行方就可以這么驗證,每次請求都去驗證下HTTP的referer字段,看是否是www.bank.com,如果是認為合法則受理請求,如果不是則拒絕。
- 優點:只需要在請求收到后添加驗證邏輯即可,對于已經有的項目來說很是方便。
- 缺點:
(1) 由于referer 的值是由瀏覽器提供的,雖然 HTTP 協議上有明確的要求,但是每個瀏覽器對于 referer 的具體實現可能有差別,并不能保證瀏覽器自身沒有安全漏洞。使用驗證 referer 值的方法,就是把安全性都依賴于第三方(即瀏覽器)來保障,從理論上來講,這樣并不安全(事實上,對于某些瀏覽器,比如 IE6 或 FF2,目前已經有一些方法可以篡改 Referer 值)。
(2) 而由于referer會記錄訪問來源,某些用戶會認為這侵犯了自己的隱私權,所以瀏覽器是允許設置發送請求的時候不提供referer。這樣就導致了銀行收不到referer從而判定請求非法而拒絕。所以此法并非萬無一失。
二、服務端驗證token信息
用戶在提交請求的時候添加服務端返回的隨機token信息,服務端判斷這個token是否與自己提供的一致,若一致則視為合法請求,否則非法。添加的方式主要有兩種:
- 往a鏈接上手動加上token參數,或在form表單中藏csrf值當用戶提交的時候隨之發送
<input name="csrf_token" type="hidden" value="abcdefg123">
- 優點:不用擔心referer被禁用問題,相比于referer的可纂改和對第三方瀏覽器依賴性較強來說更加安全可控。
- 缺點:麻煩,要給每個form和a加上這個token字段比較麻煩,容易遺漏。如果是遍歷頁面所有的a或form還要注意那種允許用戶自行填寫連接的情況。比如在博客里用戶自己寫了個a連接也被加上了token,這樣hacker也可以利用這個token為所欲為了。
- 通過 XMLHttpRequest 這個類,封裝后可以給每次請求加上 csrf_token 。
- 優點:直接一次性就給所有請求添加了token值,不用每個遍歷不擔心弄錯和遺漏。
- 缺點:對于不是采用此種 XMLHttpRequest 方式發起請求的網站來說不適用。
總結和注意要點
以上所講的方式各有優缺點,可以根據自己網站的已有情況自行選擇。但要注意以下幾點:
- token 保存在 Session 中:假如 token 保存在 cookie 中,用戶瀏覽器開了很多頁面。在一些頁面 token 被使用消耗掉后新的 token 會被重新種入,但那些老的 Tab 頁面對應的 HTML 里還是老 token。由于token變成新的,這就會導致用戶幾分鐘前打開的頁面(存的是老token)不能正常提交使用。
-
盡量少用 GET:正如上面的搶紅包例子,當用戶點擊之后,hacker可以獲得referer網址來源信息,而對于 GET 請求來說,參數是直接加到鏈接后的,所以來源
url 為www.bank.com?csrf_token=abcdefg123,所以hacker就可以獲得用戶的 token 信息做一些操作了。