CSRF是什么良姆?
(Cross Site Request Forgery, 跨站域請求偽造)是一種網(wǎng)絡(luò)的攻擊方式爵赵,它在 2007 年曾被列為互聯(lián)網(wǎng) 20 大安全隱患之一,也被稱為“One Click Attack”或者Session Riding,通常縮寫為CSRF或者XSRF玻驻,是一種對網(wǎng)站的惡意利用也就是人們所知道的釣魚網(wǎng)站。盡管聽起來像跨站腳本(XSS)违帆,但它與XSS非常不同挣磨,并且攻擊方式幾乎相左。XSS利用站點內(nèi)的信任用戶劣摇,而CSRF則通過偽裝來自受信任用戶的請求來利用受信任的網(wǎng)站珠移。與XSS攻擊相比,CSRF攻擊往往不大流行(因此對其進行防范的資源也相當(dāng)稀少)和難以防范,所以被認為比XSS更具危險性钧惧。
CSRF可以做什么暇韧?
你這可以這么理解 CSRF
攻擊:攻擊者盜用了你的身份,偽裝成你發(fā)送惡意請求浓瞪。CSRF能夠做的事情包括:以你名義發(fā)送郵件懈玻,發(fā)消息,盜取你的賬號乾颁,甚至于購買商品涂乌,虛擬貨幣轉(zhuǎn)賬......造成的問題包括:個人隱私泄露以及財產(chǎn)安全。
它這么厲害钮孵,那它的原理是什么骂倘?
通過下圖來簡述原理
登錄受信任網(wǎng)站A,并在本地生成Cookie巴席。
在不登出A的情況下历涝,訪問危險網(wǎng)站B。
看到這里漾唉,你也許會說:“如果我不滿足以上兩個條件中的一個荧库,我就不會受到CSRF的攻擊”。是的赵刑,確實如此分衫,但你不能保證以下情況不會發(fā)生:
1.你不能保證你登錄了一個網(wǎng)站后,不再打開一個tab頁面并訪問另外的網(wǎng)站般此。
2.你不能保證你關(guān)閉瀏覽器了后蚪战,你本地的Cookie立刻過期,你上次的會話已經(jīng)結(jié)束铐懊。(事實上邀桑,關(guān)閉瀏覽器不能結(jié)束一個會話,但大多數(shù)人都會錯誤的認為關(guān)閉瀏覽器就等于退出登錄/結(jié)束會話了......)
3.上圖中所謂的攻擊網(wǎng)站科乎,可能是一個存在其他漏洞的可信任的經(jīng)常被人訪問的網(wǎng)站壁畸。
詳細的原理介紹
幾種常見的攻擊類型
GET類型的CSRF
這種類型的CSRF一般是由于程序員安全意識不強造成的。GET類型的CSRF利用非常簡單茅茂,只需要一個HTTP請求捏萍,所以,一般會這樣利用:
<img src=http://wooyun.org/csrf?xx=11 />
在訪問含有這個img的頁面后空闲,成功向http://wooyun.org/csrf?xx=11 發(fā)出了一次HTTP請求令杈。所以,如果將該網(wǎng)址替換為存在GET型CSRF的地址碴倾,就能完成攻擊了逗噩。
烏云案例
POST類型的CSRF
這種類型的CSRF危害沒有GET型的大悔常,利用起來通常使用的是一個自動提交的表單,如:
<form action=http://wooyun.org/csrf.php method=POST>
<input type="text" name="xx" value="11" />
</form>
<script> document.forms[0].submit(); </script>
訪問該頁面后给赞,表單會自動提交,相當(dāng)于模擬用戶完成了一次POST操作矫户。
烏云案例
其他其他猥瑣流CSRF
過基礎(chǔ)認證的CSRF(常用于路由器):
POC:
<img src=http://admin:admin@192.168.1.1 />
加載該圖片后片迅,路由器會給用戶一個合法的SESSION,就可以進行下一步操作了皆辽。
烏云案例
防御CSRF的策略
在業(yè)界目前防御 CSRF 攻擊主要有三種策略:驗證 HTTP Referer 字段柑蛇;在請求地址中添加 token 并驗證;在 HTTP 頭中自定義屬性并驗證驱闷。下面就分別對這三種策略進行詳細介紹耻台。
驗證 HTTP Referer 字段
根據(jù) HTTP 協(xié)議,在 HTTP 頭中有一個字段叫 Referer空另,它記錄了該 HTTP 請求的來源地址盆耽。在通常情況下,訪問一個安全受限頁面的請求來自于同一個網(wǎng)站扼菠,比如需要訪問 http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory
摄杂,用戶必須先登陸 bank.example,然后通過點擊頁面上的按鈕來觸發(fā)轉(zhuǎn)賬事件循榆。因此析恢,要防御 CSRF 攻擊,網(wǎng)站只需要對于每一個轉(zhuǎn)賬請求驗證其 Referer 值秧饮,如果是以 bank.example 開頭的域名映挂,則說明該請求是來自銀行網(wǎng)站自己的請求,是合法的盗尸。如果 Referer 是其他網(wǎng)站的話柑船,則有可能是黑客的 CSRF 攻擊,拒絕該請求振劳。
這種方法的顯而易見的好處就是簡單易行椎组,網(wǎng)站的普通開發(fā)人員不需要操心 CSRF 的漏洞,只需要在最后給所有安全敏感的請求統(tǒng)一增加一個攔截器來檢查 Referer 的值就可以历恐。
然而寸癌,這種方法并非萬無一失。Referer 的值是由瀏覽器提供的弱贼,雖然 HTTP 協(xié)議上有明確的要求蒸苇,但是每個瀏覽器對于 Referer 的具體實現(xiàn)可能有差別,并不能保證瀏覽器自身沒有安全漏洞吮旅。使用驗證 Referer 值的方法溪烤,就是把安全性都依賴于第三方(即瀏覽器)來保障味咳,從理論上來講,這樣并不安全檬嘀。事實上槽驶,對于某些瀏覽器,比如IE6 或 FF2鸳兽,目前已經(jīng)有一些方法可以篡改 Referer 值掂铐。如果 網(wǎng)站支持IE6 瀏覽器,黑客完全可以把用戶瀏覽器的 Referer 值設(shè)為以 bank.example 域名開頭的地址揍异,這樣就可以通過驗證全陨,從而進行 CSRF 攻擊。
即便是使用最新的瀏覽器衷掷,黑客無法篡改 Referer 值辱姨,這種方法仍然有問題。因為 Referer 值會記錄下用戶的訪問來源戚嗅,有些用戶認為這樣會侵犯到他們自己的隱私權(quán)雨涛,特別是有些組織擔(dān)心 Referer 值會把組織內(nèi)網(wǎng)中的某些信息泄露到外網(wǎng)中。因此懦胞,用戶自己可以設(shè)置瀏覽器使其在發(fā)送請求時不再提供 Referer镜悉。當(dāng)他們正常訪問銀行網(wǎng)站時,網(wǎng)站會因為請求沒有 Referer 值而認為是 CSRF 攻擊医瘫,拒絕合法用戶的訪問侣肄。
在請求地址中添加 token 并驗證
CSRF 攻擊之所以能夠成功,是因為黑客可以完全偽造用戶的請求醇份,該請求中所有的用戶驗證信息都是存在于 cookie 中稼锅,因此黑客可以在不知道這些驗證信息的情況下直接利用用戶自己的 cookie 來通過安全驗證。要抵御 CSRF僚纷,關(guān)鍵在于在請求中放入黑客所不能偽造的信息矩距,并且該信息不存在于 cookie 之中〔澜撸可以在 HTTP 請求中以參數(shù)的形式加入一個隨機產(chǎn)生的 token锥债,并在服務(wù)器端建立一個攔截器來驗證這個 token,如果請求中沒有 token 或者 token 內(nèi)容不正確痊臭,則認為可能是 CSRF 攻擊而拒絕該請求哮肚。
這種方法要比檢查 Referer 要安全一些,token 可以在用戶登陸后產(chǎn)生并放于 session 之中广匙,然后在每次請求時把 token 從 session 中拿出允趟,與請求中的 token 進行比對,但這種方法的難點在于如何把 token 以參數(shù)的形式加入請求鸦致。對于 GET 請求潮剪,token 將附在請求地址之后涣楷,這樣 URL 就變成 http://url?csrftoken=tokenvalue
。 而對于 POST 請求來說抗碰,要在 form 的最后加上 <input type=”hidden” name=”csrftoken” value=”tokenvalue”/>
狮斗,這樣就把 token 以參數(shù)的形式加入請求了。但是弧蝇,在一個網(wǎng)站中情龄,可以接受請求的地方非常多,要對于每一個請求都加上 token 是很麻煩的捍壤,并且很容易漏掉,通常使用的方法就是在每次頁面加載時鞍爱,使用 javascript 遍歷整個 dom 樹鹃觉,對于 dom 中所有的 a 和 form 標簽后加入 token。這樣可以解決大部分的請求睹逃,但是對于在頁面加載之后動態(tài)生成的 html 代碼盗扇,這種方法就沒有作用,還需要程序員在編碼時手動添加 token沉填。
該方法還有一個缺點是難以保證 token 本身的安全疗隶。特別是在一些論壇之類支持用戶自己發(fā)表內(nèi)容的網(wǎng)站,黑客可以在上面發(fā)布自己個人網(wǎng)站的地址翼闹。由于系統(tǒng)也會在這個地址后面加上 token斑鼻,黑客可以在自己的網(wǎng)站上得到這個 token,并馬上就可以發(fā)動 CSRF 攻擊猎荠。為了避免這一點坚弱,系統(tǒng)可以在添加 token 的時候增加一個判斷,如果這個鏈接是鏈到自己本站的关摇,就在后面添加 token荒叶,如果是通向外網(wǎng)則不加。不過输虱,即使這個 csrftoken 不以參數(shù)的形式附加在請求之中些楣,黑客的網(wǎng)站也同樣可以通過 Referer 來得到這個 token 值以發(fā)動 CSRF 攻擊。這也是一些用戶喜歡手動關(guān)閉瀏覽器 Referer 功能的原因宪睹。
在 HTTP 頭中自定義屬性并驗證
這種方法也是使用 token 并進行驗證愁茁,和上一種方法不同的是,這里并不是把 token 以參數(shù)的形式置于 HTTP 請求之中亭病,而是把它放到 HTTP 頭中自定義的屬性里埋市。通過 XMLHttpRequest 這個類,可以一次性給所有該類請求加上 csrftoken 這個 HTTP 頭屬性命贴,并把 token 值放入其中道宅。這樣解決了上種方法在請求中加入 token 的不便食听,同時,通過 XMLHttpRequest 請求的地址不會被記錄到瀏覽器的地址欄污茵,也不用擔(dān)心 token 會透過 Referer 泄露到其他網(wǎng)站中去樱报。
然而這種方法的局限性非常大。XMLHttpRequest 請求通常用于 Ajax 方法中對于頁面局部的異步刷新泞当,并非所有的請求都適合用這個類來發(fā)起迹蛤,而且通過該類請求得到的頁面不能被瀏覽器所記錄下,從而進行前進襟士,后退盗飒,刷新,收藏等操作陋桂,給用戶帶來不便逆趣。另外,對于沒有進行 CSRF 防護的遺留系統(tǒng)來說嗜历,要采用這種方法來進行防護宣渗,要把所有請求都改為 XMLHttpRequest 請求,這樣幾乎是要重寫整個網(wǎng)站梨州,這代價無疑是不能接受的痕囱。
防御實例
Sailajs框架中的JavaScript 代碼示例
下面將以 JavaScript 為例,對上述三種方法分別用代碼進行示例暴匠。
1.驗證 Referer
// 從 HTTP 頭中取得 Referer 值
var referer=req.headers.Referer;
// 判斷 Referer 是否以 test.example 開頭
if((referer!=null) && (_.startsWith(referer, “test.example ”)){
// 驗證通過
}else{
// 驗證失敗鞍恢,返回錯誤
}
2.驗證請求中的 token
var session = req.session;
// 從 session 中得到 csrftoken 屬性
var token = session.csrftoken;
if(token == null){
// 產(chǎn)生新的 token 放入 session 中
token = generateToken();
token.csrftoken = token ;
return ....
} else{
// 從 HTTP 頭中取得 csrftoken
var token = req.headers.csrftoken;
// 從請求參數(shù)中取得 csrftoken
var xhrToken = req.param('csrftoken');
if(token != null && xhrToken != null && token.equals(xhrToken)){
return ...
}else{
return ... // ERROR
}
}
HTTP 頭中自定義屬性(網(wǎng)上例子)
var plainXhr = dojo.xhr;
// 重寫 dojo.xhr 方法
dojo.xhr = function(method,args,hasBody) {
// 確保 header 對象存在
args.headers = args.header || {};
tokenValue = '<%=request.getSession(false).getAttribute("csrftoken")%>';
var token = dojo.getObject("tokenValue");
// 把 csrftoken 屬性放到頭中
args.headers["csrftoken"] = (token) ? token : " ";
return plainXhr(method,args,hasBody);
};
總結(jié)
CSRF 是一種危害非常大的攻擊,又很難以防范每窖。目前幾種防御策略雖然可以很大程度上抵御 CSRF 的攻擊有序,但并沒有一種完美的解決方案。一些新的方案正在研究之中岛请,比如對于每次請求都使用不同的動態(tài)口令旭寿,把 Referer 和 token 方案結(jié)合起來,甚至嘗試修改 HTTP 規(guī)范崇败,但是這些新的方案尚不成熟盅称,要正式投入使用并被業(yè)界廣為接受還需時日。在這之前后室,我們只有充分重視 CSRF缩膝,根據(jù)系統(tǒng)的實際情況選擇最合適的策略,這樣才能把 CSRF 的危害降到最低