百度百科中的CSRF
CSRF(Cross-site request forgery)跨站請(qǐng)求偽造,也被稱為“One Click Attack”或者Session Riding,通常縮寫(xiě)為CSRF或者XSRF,是一種對(duì)網(wǎng)站的惡意利用。盡管聽(tīng)起來(lái)像跨站腳本(XSS),但它與XSS非常不同,XSS利用站點(diǎn)內(nèi)的信任用戶,而CSRF則通過(guò)偽裝來(lái)自受信任用戶的請(qǐng)求來(lái)利用受信任的網(wǎng)站。與XSS攻擊相比,CSRF攻擊往往不大流行(因此對(duì)其進(jìn)行防范的資源也相當(dāng)稀少)和難以防范,所以被認(rèn)為比XSS更具危險(xiǎn)性。
攻擊者盜用了你的身份,以你的名義發(fā)送惡意請(qǐng)求,對(duì)服務(wù)器來(lái)說(shuō)這個(gè)請(qǐng)求是完全合法的,但是卻完成了攻擊者所期望的一個(gè)操作,比如以你的名義發(fā)送郵件、發(fā)消息,盜取你的賬號(hào),添加系統(tǒng)管理員,甚至于購(gòu)買(mǎi)商品、虛擬貨幣轉(zhuǎn)賬等。
CSRF和XSS的工作原理
XSS:
攻擊者發(fā)現(xiàn)XSS漏洞——構(gòu)造代碼——發(fā)送給受害人——受害人打開(kāi)——攻擊者獲取受害人的cookie——完成攻擊
CSRF:
攻擊者發(fā)現(xiàn)CSRF漏洞——構(gòu)造代碼——發(fā)送給受害人——受害人打開(kāi)——受害人執(zhí)行代碼——完成攻擊
而且XSS容易發(fā)現(xiàn),因?yàn)楣粽咝枰卿浐笈_(tái)完成攻擊。管理員可以看日志發(fā)現(xiàn)攻擊者。????
??而CSRF則不同,他的攻擊一直是管理員自己實(shí)現(xiàn)的,攻擊者只負(fù)責(zé)了構(gòu)造代碼。??CSRF少了一個(gè) 獲取受害人的cookie的步驟,因?yàn)槭芎θ嗽趫?zhí)行代碼的時(shí)候就已經(jīng)完成的攻擊,而攻擊者并沒(méi)有參與進(jìn)來(lái)。??
CSRF的本質(zhì)
CSRF為什么能夠攻擊成功,其本質(zhì)原因是重要操作的所有參數(shù)都是可以被攻擊者猜測(cè)到的。
攻擊者只有預(yù)測(cè)出URL的所有參數(shù)與參數(shù)值,才能成功地構(gòu)造出一個(gè)偽造的請(qǐng)求;反之,攻擊者將無(wú)法攻擊成功。
因此引入了Anti CSRF Token
保持原參數(shù)不變,新增一個(gè)參數(shù)Token。這個(gè)Token的值是隨機(jī)的,不可預(yù)測(cè)的。
Token需要足夠隨機(jī),必須使用足夠安全的隨機(jī)數(shù)生成算法,或者采用真隨機(jī)數(shù)生成器。Token應(yīng)該作為一個(gè)”秘密“, 為用戶與服務(wù)器所共同持有的,不能被第三者知曉。
由于Token的存在,攻擊者無(wú)法再構(gòu)造出一個(gè)完整的URL實(shí)施CSRF攻擊。
Token需要同時(shí)放在表單和Session中。在提交表單的時(shí)候,服務(wù)器只需要驗(yàn)證表單中的Token與用戶Session(或COOKIE)中的Token是否一致,如果一致,則認(rèn)為是合法請(qǐng)求;如果不一致,或者有一個(gè)為空,則認(rèn)為請(qǐng)求不合法,可能發(fā)生了CSRF攻擊。
CSRF可以做什么
攻擊者盜用了你的身份,以你的名義發(fā)送惡意請(qǐng)求。
CSRF能夠做的事情包括:以你名義發(fā)送郵件,發(fā)消息,盜取你的賬號(hào),甚至于購(gòu)買(mǎi)商品,虛擬貨幣轉(zhuǎn)賬……造成的問(wèn)題包括:個(gè)人隱私泄露以及財(cái)產(chǎn)安全。
實(shí)例
如下:其中Web A為存在CSRF漏洞的網(wǎng)站,Web B為攻擊者構(gòu)建的惡意網(wǎng)站,User C為Web A網(wǎng)站的合法用戶。
- 用戶C打開(kāi)瀏覽器,訪問(wèn)受信任網(wǎng)站A,輸入用戶名和密碼請(qǐng)求登錄網(wǎng)站A;
2.在用戶信息通過(guò)驗(yàn)證后,網(wǎng)站A產(chǎn)生Cookie信息并返回給瀏覽器,此時(shí)用戶登錄網(wǎng)站A成功,可以正常發(fā)送請(qǐng)求到網(wǎng)站A;
用戶未退出網(wǎng)站A之前,在同一瀏覽器中,打開(kāi)一個(gè)TAB頁(yè)訪問(wèn)網(wǎng)站B;
網(wǎng)站B接收到用戶請(qǐng)求后,返回一些攻擊性代碼,并發(fā)出一個(gè)請(qǐng)求要求訪問(wèn)第三方站點(diǎn)A;
瀏覽器在接收到這些攻擊性代碼后,根據(jù)網(wǎng)站B的請(qǐng)求,在用戶不知情的情況下攜帶Cookie信息,向網(wǎng)站A發(fā)出請(qǐng)求。網(wǎng)站A并不知道該請(qǐng)求其實(shí)是由B發(fā)起的,所以會(huì)根據(jù)用戶C的Cookie信息以C的權(quán)限處理該請(qǐng)求,導(dǎo)致來(lái)自網(wǎng)站B的惡意代碼被執(zhí)行。
比較好的攻擊實(shí)例
圖片.png
GET?POST?
GET類(lèi)型CSRF
<img src=http://xxx.org/csrf.php?xx=1 />
訪問(wèn)頁(yè)面后就成功向http://xxx.org/csrf.php 發(fā)送了一次請(qǐng)求
<link href="…">
<iframe src="…">
<meta http-equiv="refresh" content="0; url=…">
<script src="…">
<video src="…">
<audio src="…">
<a href="…">
<table background="…">
POST類(lèi)型CSRF
使用一個(gè)自動(dòng)提交的表單
<form action=http://woyun.org/csrf.php method=POST>
<input type="text" name='xx' value='11' />
</form>
<script>document.forms[0].submit();</script>
模擬用戶完成了一次POST操作
也可以用JS動(dòng)態(tài)生成
<script>
new Image().src = 'http://192.168.0.100/joomla';
</script>
大多數(shù)CSRF攻擊發(fā)起時(shí),使用的HTML標(biāo)簽都是<img>,<iframe>,<script>等帶"src"屬性的標(biāo)簽,這類(lèi)標(biāo)簽只能夠發(fā)一起一次GET請(qǐng)求,而不能發(fā)起POST請(qǐng)求。而對(duì)于很多網(wǎng)站的應(yīng)用來(lái)說(shuō),一些重要的操作并未嚴(yán)格的區(qū)分GET和POST,攻擊者可以使用GET來(lái)請(qǐng)求表單的提交地址。比如在PHP中,如果使用的是$_REQUEST,而非$_POST來(lái)獲取變量,也會(huì)存在這個(gè)問(wèn)題。
如果服務(wù)端已經(jīng)區(qū)分了GET與POST,對(duì)于攻擊者來(lái)說(shuō)有若干種方法可以構(gòu)造出一個(gè)POST請(qǐng)求:
最簡(jiǎn)單的方法就是在一個(gè)頁(yè)面中構(gòu)造好一個(gè)form表單,然后使用JavaScript自動(dòng)提交這個(gè)表單。
<form action="http://www.a.com/test/" id="test" method="post">
<input type=text name="username" value="" />
<input type=password name="password" value="" />
<input type= submit name="submit" value="submit" />
</form>
<script>
var f=document.getElementById("test");
f.inputs[0].value="test";
f.inputs[1].value="password";
f.submit();
</script>
瀏覽器的COOKIE策略
瀏覽器所持有的COOKIE分為兩種,一種是"Session Cookie",又稱“臨時(shí)COOKIE”;另一種是“Tird-party-COOKIE”,也稱為“本地COOKIE”。
兩者的區(qū)別在于,Third-party COOKIE是服務(wù)器在Set-COOKIE時(shí)指定了Expire時(shí)間,只有到了Expire時(shí)間后COOKIE才會(huì)失效,所以這種COOKIE會(huì)保存在本地;而Session COOKIE則沒(méi)有指定Expire時(shí)間,所以瀏覽器關(guān)閉后,Session COOKIE就失效了。
若一個(gè)網(wǎng)站設(shè)置了Session COOKIE,那么在瀏覽器進(jìn)程的生命周期內(nèi),即使瀏覽器新打開(kāi)了Tab頁(yè),Session COOKIE也是有效的。Session COOKIE保存在瀏覽器進(jìn)程的內(nèi)存空間中;而Third-party COOKIE則保存在本地。
如果瀏覽器從一個(gè)域的頁(yè)面加載另一個(gè)域的資源,由于安全原因。某些瀏覽器會(huì)組織Third-party COOKIE的發(fā)送。
在Friefox中,默認(rèn)策略是允許發(fā)送第三方COOKIE的。
所以對(duì)于IE瀏覽器,攻擊者則需要精心構(gòu)造攻擊環(huán)境,比如誘使用戶在當(dāng)前瀏覽器中先訪問(wèn)目標(biāo)站點(diǎn),使得Session COOKIE有效,再實(shí)施CSRF攻擊。
P3P Header
如果網(wǎng)站返回給瀏覽器的HTTP頭中包含有P3P頭,則在某種程度上來(lái)說(shuō),將允許瀏覽器發(fā)送第三方COOKIE。在IE下即使是<iframe>、<script>等標(biāo)簽也將不再攔截第三方COOKIE的發(fā)送。JSON劫持攻擊
Json和Jsonp理論實(shí)例代碼詳解
JSON劫持漏洞攻防原理及演練
深入理解JavaScript Hijacking原理
一些web應(yīng)用會(huì)把一些敏感數(shù)據(jù)以json的形式返回到前端,如果僅僅通過(guò)cookie來(lái)判斷請(qǐng)求是否合法,那么就可以利用類(lèi)似csrf的手段,像目標(biāo)服務(wù)器發(fā)送請(qǐng)求,以獲得敏感數(shù)據(jù)。
(1).你正常訪問(wèn)信任站點(diǎn)(http://www.Bank.com),然后登陸信任站點(diǎn)。
(2).信任站點(diǎn)通過(guò)你的驗(yàn)證,并返回Cookie。
(3).這時(shí),在你還沒(méi)有登出信任站點(diǎn)之前,你再打開(kāi)了一個(gè)瀏覽器的tab頁(yè),并訪問(wèn)了一個(gè)惡意站點(diǎn)(www.BadGuy.com)。
(4).惡意站點(diǎn)向請(qǐng)求用戶訪問(wèn)http://www.Bank.com的一個(gè)資源。
(5).瀏覽器帶著之前的Cookie信息,向信任站點(diǎn)http://www.Bank.com發(fā)出了一個(gè)GET請(qǐng)求。
(6).信任站點(diǎn)驗(yàn)證的Cookie信息通過(guò),根據(jù)請(qǐng)求返回一個(gè)JSON數(shù)組
(7).你的瀏覽器收到來(lái)自http://www.Bank.com的響應(yīng)后,轉(zhuǎn)發(fā)響應(yīng)中的JSON信息給惡意站點(diǎn)。
至此,惡意站點(diǎn)拿到你關(guān)于http://www.Bank.com的信息。
到這里,你應(yīng)該有對(duì)JavaScript Hijacking有一個(gè)大概的概念,它確實(shí)和CSRF很相像,唯一不同的是,CSRF是模擬你的身份去發(fā)送請(qǐng)求,JavaScript Hijacking是模擬你的身份,竊取你在服務(wù)器上的私隱信息。
比較詳細(xì)的描述防御CSRF攻擊:
(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 的最后加上 <input type=”hidden” name=”csrftoken” value=”tokenvalue”/>,這樣就把 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 本身的安全。特別是在一些論壇之類(lèi)支持用戶自己發(fā)表內(nèi)容的網(wǎng)站,黑客可以在上面發(fā)布自己個(gè)人網(wǎng)站的地址。由于系統(tǒng)也會(huì)在這個(gè)地址后面加上 token,黑客可以在自己的網(wǎng)站上得到這個(gè) token,并馬上就可以發(fā)動(dòng) CSRF 攻擊。為了避免這一點(diǎn),系統(tǒng)可以在添加 token 的時(shí)候增加一個(gè)判斷,如果這個(gè)鏈接是鏈到自己本站的,就在后面添加 token,如果是通向外網(wǎng)則不加。不過(guò),即使這個(gè) csrftoken 不以參數(shù)的形式附加在請(qǐng)求之中,黑客的網(wǎng)站也同樣可以通過(guò) Referer 來(lái)得到這個(gè) token 值以發(fā)動(dòng) CSRF 攻擊。這也是一些用戶喜歡手動(dòng)關(guān)閉瀏覽器 Referer 功能的原因。
(3)在 HTTP 頭中自定義屬性并驗(yàn)證
這種方法也是使用 token 并進(jìn)行驗(yàn)證,和上一種方法不同的是,這里并不是把 token 以參數(shù)的形式置于 HTTP 請(qǐng)求之中,而是把它放到 HTTP 頭中自定義的屬性里。通過(guò) XMLHttpRequest 這個(gè)類(lèi),可以一次性給所有該類(lèi)請(qǐng)求加上 csrftoken 這個(gè) HTTP 頭屬性,并把 token 值放入其中。這樣解決了上種方法在請(qǐng)求中加入 token 的不便,同時(shí),通過(guò) XMLHttpRequest 請(qǐng)求的地址不會(huì)被記錄到瀏覽器的地址欄,也不用擔(dān)心 token 會(huì)透過(guò) Referer 泄露到其他網(wǎng)站中去。
然而這種方法的局限性非常大。XMLHttpRequest 請(qǐng)求通常用于 Ajax 方法中對(duì)于頁(yè)面局部的異步刷新,并非所有的請(qǐng)求都適合用這個(gè)類(lèi)來(lái)發(fā)起,而且通過(guò)該類(lèi)請(qǐng)求得到的頁(yè)面不能被瀏覽器所記錄下,從而進(jìn)行前進(jìn),后退,刷新,收藏等操作,給用戶帶來(lái)不便。另外,對(duì)于沒(méi)有進(jìn)行 CSRF 防護(hù)的遺留系統(tǒng)來(lái)說(shuō),要采用這種方法來(lái)進(jìn)行防護(hù),要把所有請(qǐng)求都改為 XMLHttpRequest 請(qǐng)求,這樣幾乎是要重寫(xiě)整個(gè)網(wǎng)站,這代價(jià)無(wú)疑是不能接受的。
(4)驗(yàn)證碼
參考文獻(xiàn)
《白帽子講WEB安全》
CSRF攻擊與防御(寫(xiě)得非常好)