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