行業(yè)資訊
什么是CSRF?CSRF是一種對(duì)網(wǎng)站的惡意利用,CSRF比XSS更具危險(xiǎn)性,攻擊者盜用了你的身份,以你的名義發(fā)送惡意請(qǐng)求,對(duì)服務(wù)器來(lái)說(shuō)這個(gè)請(qǐng)求是完全合法的,但是卻完成了攻擊者所期望的一個(gè)操作,比如以你的名義發(fā)送郵件、發(fā)消息,盜取你的賬號(hào),添加系統(tǒng)管理員,甚至于購(gòu)買商品、虛擬貨幣轉(zhuǎn)賬等。
服務(wù)器防御方案:http://www.xcwl17.com/network/cdn.html
CSRF攻擊的主要目的是讓用戶在不知情的情況下攻擊自己已登錄的一個(gè)系統(tǒng),類似于釣魚(yú)。如用戶當(dāng)前已經(jīng)登錄了郵箱,或bbs,同時(shí)用戶又在使用另外一個(gè),已經(jīng)被你控制的站點(diǎn),我們姑且叫它釣魚(yú)網(wǎng)站。這個(gè)網(wǎng)站上面可能因?yàn)槟硞€(gè)圖片吸引你,你去點(diǎn)擊一下,此時(shí)可能就會(huì)觸發(fā)一個(gè)js的點(diǎn)擊事件,構(gòu)造一個(gè)bbs發(fā)帖的請(qǐng)求,去往你的bbs發(fā)帖,由于當(dāng)前你的瀏覽器狀態(tài)已經(jīng)是登陸狀態(tài),所以session登陸cookie信息都會(huì)跟正常的請(qǐng)求一樣,純天然的利用當(dāng)前的登陸狀態(tài),讓用戶在不知情的情況下,幫你發(fā)帖或干其他事情。
CSRF攻擊原理
從上圖可以看出,要完成一次CSRF攻擊,受害者必須依次完成兩個(gè)步驟:
1.登錄受信任網(wǎng)站A,并在本地生成Cookie。
2.在不登出A的情況下,訪問(wèn)危險(xiǎn)網(wǎng)站B。
看到這里,你也許會(huì)說(shuō):“如果我不滿足以上兩個(gè)條件中的一個(gè),我就不會(huì)受到CSRF的攻擊”。是的,確實(shí)如此,但你不能保證以下情況不會(huì)發(fā)生:
1.你不能保證你登錄了一個(gè)網(wǎng)站后,不再打開(kāi)一個(gè)tab頁(yè)面并訪問(wèn)另外的網(wǎng)站。
2.你不能保證你關(guān)閉瀏覽器了后,你本地的Cookie立刻過(guò)期,你上次的會(huì)話已經(jīng)結(jié)束。(事實(shí)上,關(guān)閉瀏覽器不能結(jié)束一個(gè)會(huì)話,但大多數(shù)人都會(huì)錯(cuò)誤的認(rèn)為關(guān)閉瀏覽器就等于退出登錄/結(jié)束會(huì)話了......)
3.上圖中所謂的攻擊網(wǎng)站,可能是一個(gè)存在其他漏洞的可信任的經(jīng)常被人訪問(wèn)的網(wǎng)站。
防御CSRF攻擊:
目前防御 CSRF 攻擊主要有三種策略:驗(yàn)證 HTTP Referer 字段;在請(qǐng)求地址中添加 token 并驗(yàn)證;在 HTTP 頭中自定義屬性并驗(yàn)證。
(1)驗(yàn)證 HTTP Referer 字段
根據(jù) HTTP 協(xié)議,在 HTTP 頭中有一個(gè)字段叫 Referer,它記錄了該 HTTP 請(qǐng)求的來(lái)源地址。在通常情況下,訪問(wèn)一個(gè)安全受限頁(yè)面的請(qǐng)求來(lái)自于同一個(gè)網(wǎng)站,比如需要訪問(wèn) http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory,用戶必須先登陸 bank.example,然后通過(guò)點(diǎn)擊頁(yè)面上的按鈕來(lái)觸發(fā)轉(zhuǎn)賬事件。這時(shí),該轉(zhuǎn)帳請(qǐng)求的 Referer 值就會(huì)是轉(zhuǎn)賬按鈕所在的頁(yè)面的 URL,通常是以 bank.example 域名開(kāi)頭的地址。而如果黑客要對(duì)銀行網(wǎng)站實(shí)施 CSRF 攻擊,他只能在他自己的網(wǎng)站構(gòu)造請(qǐng)求,當(dāng)用戶通過(guò)黑客的網(wǎng)站發(fā)送請(qǐng)求到銀行時(shí),該請(qǐng)求的 Referer 是指向黑客自己的網(wǎng)站。因此,要防御 CSRF 攻擊,銀行網(wǎng)站只需要對(duì)于每一個(gè)轉(zhuǎn)賬請(qǐng)求驗(yàn)證其 Referer 值,如果是以 bank.example 開(kāi)頭的域名,則說(shuō)明該請(qǐng)求是來(lái)自銀行網(wǎng)站自己的請(qǐng)求,是合法的。如果 Referer 是其他網(wǎng)站的話,則有可能是黑客的 CSRF 攻擊,拒絕該請(qǐng)求。
這種方法的顯而易見(jiàn)的好處就是簡(jiǎn)單易行,網(wǎng)站的普通開(kāi)發(fā)人員不需要操心 CSRF 的漏洞,只需要在最后給所有安全敏感的請(qǐng)求統(tǒng)一增加一個(gè)攔截器來(lái)檢查 Referer 的值就可以。特別是對(duì)于當(dāng)前現(xiàn)有的系統(tǒng),不需要改變當(dāng)前系統(tǒng)的任何已有代碼和邏輯,沒(méi)有風(fēng)險(xiǎn),非常便捷。
然而,這種方法并非萬(wàn)無(wú)一失。Referer 的值是由瀏覽器提供的,雖然 HTTP 協(xié)議上有明確的要求,但是每個(gè)瀏覽器對(duì)于 Referer 的具體實(shí)現(xiàn)可能有差別,并不能保證瀏覽器自身沒(méi)有安全漏洞。使用驗(yàn)證 Referer 值的方法,就是把安全性都依賴于第三方(即瀏覽器)來(lái)保障,從理論上來(lái)講,這樣并不安全。事實(shí)上,對(duì)于某些瀏覽器,比如 IE6 或 FF2,目前已經(jīng)有一些方法可以篡改 Referer 值。如果 bank.example 網(wǎng)站支持 IE6 瀏覽器,黑客完全可以把用戶瀏覽器的 Referer 值設(shè)為以 bank.example 域名開(kāi)頭的地址,這樣就可以通過(guò)驗(yàn)證,從而進(jìn)行 CSRF 攻擊。
即便是使用最新的瀏覽器,黑客無(wú)法篡改 Referer 值,這種方法仍然有問(wèn)題。因?yàn)?Referer 值會(huì)記錄下用戶的訪問(wèn)來(lái)源,有些用戶認(rèn)為這樣會(huì)侵犯到他們自己的隱私權(quán),特別是有些組織擔(dān)心 Referer 值會(huì)把組織內(nèi)網(wǎng)中的某些信息泄露到外網(wǎng)中。因此,用戶自己可以設(shè)置瀏覽器使其在發(fā)送請(qǐng)求時(shí)不再提供 Referer。當(dāng)他們正常訪問(wèn)銀行網(wǎng)站時(shí),網(wǎng)站會(huì)因?yàn)檎?qǐng)求沒(méi)有 Referer 值而認(rèn)為是 CSRF 攻擊,拒絕合法用戶的訪問(wèn)。
(2)在請(qǐng)求地址中添加 token 并驗(yàn)證
CSRF 攻擊之所以能夠成功,是因?yàn)楹诳涂梢酝耆珎卧煊脩舻恼?qǐng)求,該請(qǐng)求中所有的用戶驗(yàn)證信息都是存在于 cookie 中,因此黑客可以在不知道這些驗(yàn)證信息的情況下直接利用用戶自己的 cookie 來(lái)通過(guò)安全驗(yàn)證。要抵御CSRF,關(guān)鍵在于在請(qǐng)求中放入黑客所不能偽造的信息,并且該信息不存在于 cookie 之中??梢栽?HTTP 請(qǐng)求中以參數(shù)的形式加入一個(gè)隨機(jī)產(chǎn)生的 token,并在服務(wù)器端建立一個(gè)攔截器來(lái)驗(yàn)證這個(gè) token,如果請(qǐng)求中沒(méi)有 token 或者 token 內(nèi)容不正確,則認(rèn)為可能是 CSRF 攻擊而拒絕該請(qǐng)求。
這種方法要比檢查 Referer 要安全一些,token 可以在用戶登陸后產(chǎn)生并放于 session 之中,然后在每次請(qǐng)求時(shí)把 token 從 session 中拿出,與請(qǐng)求中的 token 進(jìn)行比對(duì),但這種方法的難點(diǎn)在于如何把 token 以參數(shù)的形式加入請(qǐng)求。對(duì)于 GET 請(qǐng)求,token 將附在請(qǐng)求地址之后,這樣 URL 就變成 http://url?csrftoken=tokenvalue。 而對(duì)于 POST 請(qǐng)求來(lái)說(shuō),要在 form 的最后加上 ,這樣就把 token 以參數(shù)的形式加入請(qǐng)求了。但是,在一個(gè)網(wǎng)站中,可以接受請(qǐng)求的地方非常多,要對(duì)于每一個(gè)請(qǐng)求都加上 token 是很麻煩的,并且很容易漏掉,通常使用的方法就是在每次頁(yè)面加載時(shí),使用 javascript 遍歷整個(gè) dom 樹(shù),對(duì)于 dom 中所有的 a 和 form 標(biāo)簽后加入 token。
這樣可以解決大部分的請(qǐng)求,但是對(duì)于在頁(yè)面加載之后動(dòng)態(tài)生成的 html 代碼,這種方法就沒(méi)有作用,還需要程序員在編碼時(shí)手動(dòng)添加 token。該方法還有一個(gè)缺點(diǎn)是難以保證 token 本身的安全。