在前面我們說(shuō)過(guò),很多時(shí)候大部分的系統(tǒng)漏洞都是很難發(fā)現(xiàn)的,這時(shí)候大部分的黑客就會(huì)通過(guò)偽造網(wǎng)站,從而變相獲取我們的數(shù)據(jù)。這其中涉及的方式便是CSRF攻擊。
CSRF全稱(chēng)Cross Site Request Forgery,即跨站點(diǎn)請(qǐng)求偽造。我們知道,攻擊時(shí)常常伴隨著各種各樣的請(qǐng)求,而攻擊的發(fā)生也是由各種請(qǐng)求造成的。
從前面這個(gè)名字里我們可以關(guān)注到兩個(gè)點(diǎn):一個(gè)是“跨站點(diǎn)”,另一個(gè)是“偽造”。前者說(shuō)明了CSRF攻擊發(fā)生時(shí)所伴隨的請(qǐng)求的來(lái)源,后者說(shuō)明了該請(qǐng)求的產(chǎn)生方式。所謂偽造即該請(qǐng)求并不是用戶本身的意愿,而是由攻擊者構(gòu)造,由受害者被動(dòng)發(fā)出的。
CSRF的攻擊過(guò)程大致如圖:
CSRF攻擊存在的道理
一種攻擊方式之所以能夠存在,必然是因?yàn)樗軌蜻_(dá)到某種特定的目的。比如:通過(guò)程序中的緩沖區(qū)溢出漏洞,我們可以嘗試控制程序的流程,使其執(zhí)行任意代碼;通過(guò)網(wǎng)站上的SQL注入漏洞,我們可以讀取數(shù)據(jù)庫(kù)中的敏感信息,進(jìn)而獲取Webshell甚至獲取服務(wù)器的控制權(quán)等等。而CSRF攻擊能夠達(dá)到的目的是使受害者發(fā)出由攻擊者偽造的請(qǐng)求,那么這有什么作用呢?
顯然,這種攻擊的威力和受害者的身份有著密切的聯(lián)系。說(shuō)到這兒我們可以思考一下,攻擊者之所以要偽造請(qǐng)求由受害者發(fā)出,不正是想利用受害者的身份去達(dá)到一些目的嗎?換句話說(shuō),受害者身上有達(dá)到這個(gè)目的所必需的條件,
而這些必需的條件在Web應(yīng)用中便是各種各樣的認(rèn)證信息,攻擊者就是利用這些認(rèn)證信息來(lái)實(shí)現(xiàn)其各種各樣的目的。
下面我們先看幾個(gè)攻擊場(chǎng)景。
(1)場(chǎng)景一:
在一個(gè)bbs社區(qū)里,用戶在發(fā)言的時(shí)候會(huì)發(fā)出一個(gè)這樣的GET請(qǐng)求:
#!html
GET /talk.php?msg=hello HTTP/1.1
Host: www.bbs.com
…
Cookie: PHPSESSID=ee2cb583e0b94bad4782ea
(空一行)
這是用戶發(fā)言內(nèi)容為“hello”時(shí)發(fā)出的請(qǐng)求,當(dāng)然,用戶在請(qǐng)求的同時(shí)帶上了該域下的cookie,于是攻擊者構(gòu)造了下面的csrf.html頁(yè)面:
#!html
<html>
<img src=http://www.bbs.com/talk.php?msg=goodbye />
</html>
可以看到,攻擊者在自己的頁(yè)面中構(gòu)造了一個(gè)發(fā)言的GET請(qǐng)求,然后把這個(gè)頁(yè)面放在自己的服務(wù)器上,鏈接為
http://www.evil.com/csrf.html。之后攻擊者通過(guò)某種方式誘騙受害者訪問(wèn)該鏈接,如果受害者此時(shí)處于登錄狀態(tài),就會(huì)帶上bbs.com域下含有自己認(rèn)證信息的cookie訪問(wèn)
http://www.bbs.com/talk.php?msg=goodbye,結(jié)果就是受害者按照攻擊者的意愿提交了一份內(nèi)容為“goodbye”的發(fā)言。
有人說(shuō)這有什么大不了的,好,我們?cè)倏纯戳硪粋€(gè)場(chǎng)景下的CSRF攻擊。
(2)場(chǎng)景二:
在一個(gè)CMS系統(tǒng)的后臺(tái),發(fā)出下面的POST請(qǐng)求可以執(zhí)行添加管理員的操作:
#!html
POST /manage.php?act=add HTTP/1.1
Host: www.cms.com
…
Cookie: PHPSESSID=ee2cb583e0b94bad4782ea;
is_admin=234mn9guqgpi3434f9r3msd8dkekwel
(空一行)
uname=test&pword=test
在這里,攻擊者構(gòu)造了的csrf2.html頁(yè)面如下:
#!html
<html>
<form action="/manage.php?act=add" method="post">
<input type="text" name="uname" value="evil" />
<input type="password" name="pword" value="123456" />
</form>
<script>
document.forms[0].submit();
</script>
</html>
該頁(yè)面的鏈接為
http://www.evil.com/csrf2.html,攻擊者誘騙已經(jīng)登錄后臺(tái)的網(wǎng)站管理員訪問(wèn)該鏈接(比如通過(guò)給管理員留言等方式)會(huì)發(fā)生什么呢?當(dāng)然是網(wǎng)站管理員根據(jù)攻擊者偽造的請(qǐng)求添加了一個(gè)用戶名為evil的管理員用戶。
通過(guò)這些場(chǎng)景我們可以看到,CSRF攻擊會(huì)根據(jù)場(chǎng)景的不同而危害迥異。小到誘使用戶留言,大到垂直越權(quán)進(jìn)行操作。這些攻擊的請(qǐng)求都是跨域發(fā)出,并且至關(guān)重要的一點(diǎn),都是在受害者的身份得到認(rèn)證以后發(fā)生的。
CSRF的防御
要防御CSRF攻擊,我們就要牢牢抓住CSRF攻擊的幾個(gè)特點(diǎn)。
首先是“跨域”,我們發(fā)現(xiàn)CSRF攻擊的請(qǐng)求都是跨域的,針對(duì)這一特點(diǎn),我們可以在服務(wù)端對(duì)HTTP請(qǐng)求頭部的Referer字段進(jìn)行檢查。一般情況下,用戶提交的都是站內(nèi)的請(qǐng)求,其Referer中的來(lái)源地址應(yīng)該是站內(nèi)的地址。至關(guān)重要的一點(diǎn)是,前端的JAVAScript無(wú)法修改Referer字段,這也是這種防御方法成立的條件。
不過(guò)需要說(shuō)明的是,有的時(shí)候請(qǐng)求并不需要跨域,比如我們后面講到的結(jié)合XSS進(jìn)行攻擊的時(shí)候,有的時(shí)候甚至沒(méi)有Referer字段…,這些也是使用這種防御方法的弊病所在。
第二點(diǎn)是“偽造”,這也是CSRF攻擊的核心點(diǎn),即偽造的請(qǐng)求。我們來(lái)想一下,攻擊者為什么能夠偽造請(qǐng)求呢?換句話說(shuō),攻擊者能夠偽造請(qǐng)求的條件是什么呢?縱觀之前我們偽造的所有請(qǐng)求,無(wú)一例外,請(qǐng)求中所有參數(shù)的值都是我們可以預(yù)測(cè)的,如果出現(xiàn)了攻擊者無(wú)法預(yù)測(cè)的參數(shù)值,那么將無(wú)法偽造請(qǐng)求,CSRF攻擊也不會(huì)發(fā)生。基于這一點(diǎn),可以使用添加驗(yàn)證碼和使用一次性token的方式防御此類(lèi)攻擊,但是正如世界上沒(méi)有完美的系統(tǒng)一樣,也沒(méi)有完美的防御方式,都是在不斷的變化與改進(jìn)當(dāng)中。
從上面的例子我們可以看出,制造釣魚(yú)網(wǎng)站,理論上可以獲取你瀏覽器保存的幾乎所有數(shù)據(jù)。所以,不信任的網(wǎng)站,不要輕易點(diǎn)擊。上面的例子也僅僅只是csrf最最基礎(chǔ)的應(yīng)用,但是如果是此類(lèi)攻擊,也逃不過(guò)使用這種方式。只不過(guò)會(huì)使用這種方式再加各種類(lèi)型的變種,或結(jié)合其他的攻擊方式,對(duì)其進(jìn)行攻擊。