今天,我們跟大家聊聊Web應(yīng)用的客戶端安全的故事。這個(gè)故事講述的是攻擊者如何從Web應(yīng)用的客戶端下手發(fā)動(dòng)攻擊的戰(zhàn)術(shù)。這是一種非常簡(jiǎn)單卻又令人膽寒的戰(zhàn)術(shù):之所以說(shuō)它令人膽寒是因?yàn)楣粽吣芙o其它的用戶施展攝魂大法,讓他們夢(mèng)游般的去做一些他們不想做的事情;之所以說(shuō)它簡(jiǎn)單,是因?yàn)楣粽咭脒_(dá)到上述目的,只需向用戶發(fā)送一封電子郵件或設(shè)法讓他們?nèi)ヒ粋€(gè)web頁(yè)面就足夠了。有時(shí)候,人們將這個(gè)安全問(wèn)題稱為“客戶端攻擊”——可能是受到古代木馬攻城故事的啟發(fā)吧。不過(guò)即便你對(duì)這個(gè)遙遠(yuǎn)的故事不熟也不要緊,本文將向讀者詳細(xì)解釋這個(gè)問(wèn)題,并討論可能解決。
一、Web應(yīng)用客戶端的木馬攻城
介紹這個(gè)安全問(wèn)題最好的方法就是進(jìn)行實(shí)例分析。按照循序漸進(jìn)的原則,我們首先介紹一個(gè)較為簡(jiǎn)單的例子,然后再討論更為復(fù)雜的例子,如網(wǎng)絡(luò)銀行等(是的,網(wǎng)絡(luò)銀行也同樣面臨這種威脅)。我們首先考察的是一個(gè)假想的投票站點(diǎn),該站點(diǎn)允許用戶給不同的候選人投票,并統(tǒng)計(jì)出選舉結(jié)果。用于投票的web頁(yè)面可能包含下列HTML代碼:
由于該表單使用的是GET方式,所以用戶給他心儀的候選人投票時(shí),將通過(guò)類似下面的URL來(lái)提交表單:
現(xiàn)在,攻擊者會(huì)設(shè)法誘騙其他用戶來(lái)點(diǎn)擊這些鏈接,比如復(fù)制以上URL并通過(guò)電子郵件大量發(fā)送,并向收件人聲稱這些URL鏈接到一個(gè)能誘惑人的事物上,比如非常好玩的游戲、裸體美女、聳人聽(tīng)聞的報(bào)道、有趣的笑話,等等。事實(shí)上,我們幾乎沒(méi)有辦法阻止他們這么做——諸位,有誰(shuí)沒(méi)收到過(guò)?!如果某些人點(diǎn)擊了這些鏈接,那么他們就會(huì)給攻擊者喜愛(ài)的候選人投上一票,這樣的話,統(tǒng)計(jì)結(jié)果就有貓膩了。
也許您對(duì)這個(gè)例子持有異議。首先,您可能會(huì)說(shuō),大部分用戶都不會(huì)點(diǎn)擊這樣的鏈接,因?yàn)檫@個(gè)鏈接看上去非??梢伞5菍?duì)攻擊者來(lái)說(shuō)這不是個(gè)問(wèn)題,因?yàn)樗麄兛梢允褂弥囟ㄏ蚣夹g(shù)來(lái)隱藏URL,從而迷惑更多的用戶。他可以在郵件中使用不直接指向投票站點(diǎn),而是指向其它頁(yè)面的URL,比如使用一個(gè)指向他自己的的URL:
看到鏈接中“nicejoke”,您也許以為這是一個(gè)關(guān)于笑話的頁(yè)面。實(shí)際上,與您所認(rèn)為的正好相反,這個(gè)nicejoke.html頁(yè)面中并沒(méi)有任何笑話,而是包含下列HTML代碼:
一旦讀取meta標(biāo)簽,它就會(huì)被重定向至投票頁(yè)面的URL,等用戶明白過(guò)來(lái)是怎么回事的時(shí)候,已經(jīng)為時(shí)完矣!當(dāng)然,攻擊者使用腳本或者HTTP的Location報(bào)頭的話,也能達(dá)到同樣的效果。
您對(duì)該示例持有疑議的第二個(gè)理由可能是:就本例而言,使用一個(gè)GET請(qǐng)求是錯(cuò)誤的。根據(jù)定義HTTP的RFC 2616文檔,當(dāng)動(dòng)作具有副作用(比如有安全隱患)的時(shí)候,應(yīng)該使用POST請(qǐng)求。當(dāng)使用POST后,就無(wú)法在一個(gè)URL中放入投票細(xì)節(jié),因?yàn)镻OST請(qǐng)求中的參數(shù)被隱藏在請(qǐng)求本身之中。但是這并不能阻止攻擊者的腳步——他們完全可以不去誘騙瀏覽器訪問(wèn)以上URL,而是欺騙受害者瀏覽一個(gè)自動(dòng)提交的表單,例如下面的表單:
這個(gè)名為“f”的表單包含了一個(gè)隱藏字段,其中的參數(shù)“alt”已經(jīng)被攻擊者設(shè)為他們選定的值了。表單之下是JavaScript代碼,它的作用實(shí)際上就是提交該表單,就像是用戶按下了并不存在的提交按鈕那樣。
那些壞家伙可以將這些代碼插入一個(gè)web頁(yè)面,并哄騙用戶訪問(wèn)它。這樣一來(lái),當(dāng)受害者明白過(guò)來(lái)的時(shí)候,他們已經(jīng)替別人投完票了。
更好的方法是將上述表單嵌入一封HTML編碼的電子郵件中。一些流行的電子郵件客戶端不僅能查看HTML郵件,甚至可以執(zhí)行JavaScript代碼。不幸的用戶可能僅僅由于閱讀攻擊者的郵件而神不知鬼不覺(jué)地將它們的票投給了攻擊者,如果郵件程序自動(dòng)地預(yù)覽來(lái)信的話,甚至根本都不需要閱讀郵件。
請(qǐng)注意,公司的Outlook在顯示HTML格式的電子郵件時(shí)會(huì)用到IE瀏覽器的組件。作者在Windows 2000上測(cè)試時(shí)發(fā)現(xiàn),Outlook 使用的IE實(shí)例會(huì)跟已打開(kāi)的IE共享一切,包括會(huì)話cookie。所以您一定要記住這一點(diǎn),尤其是到后文的網(wǎng)絡(luò)銀行的時(shí)候,因?yàn)檎沁@一點(diǎn)為更酷的遠(yuǎn)程控制電子郵件鋪平了道路。幸運(yùn)的是,Windows XP默認(rèn)時(shí)不會(huì)運(yùn)行嵌入HTML格式電子郵件中的腳本——至少我測(cè)試的腳本沒(méi)有被執(zhí)行。
迄今為止,我們已經(jīng)考察了一個(gè)用于投票的簡(jiǎn)單應(yīng)用程序。但是,讓人膽寒的客戶端木馬戰(zhàn)還涉及到身份驗(yàn)證。因?yàn)檫@些特洛伊木馬攻擊是通過(guò)欺騙用戶或者他的瀏覽器訪問(wèn)目標(biāo)站點(diǎn)來(lái)運(yùn)作的,所以只有用戶業(yè)已登錄到目標(biāo)站點(diǎn)的時(shí)候,特洛伊木馬才能以該用戶的名義做各種事情。
假設(shè)一個(gè)用戶已登錄到他的網(wǎng)絡(luò)銀行,而這時(shí)一個(gè)攻擊者想要冒充那個(gè)用戶來(lái)發(fā)財(cái)?shù)脑?,只要能欺騙用戶瀏覽下列內(nèi)容就足矣:
現(xiàn)在,如果受害者早已登錄到銀行,而該銀行也接受此類表單,那么該用戶就會(huì)在毫不知情的情況下把錢(qián)轉(zhuǎn)到攻擊者的帳戶上,當(dāng)然攻擊者也可以利用此特權(quán)給別人栽贓。
要做到這一點(diǎn),受害者必須已經(jīng)登錄到目標(biāo)站點(diǎn),否則攻擊者也無(wú)可奈何。然而,如果用戶選擇了“記住密碼”選項(xiàng),那么他就會(huì)一直處于登錄狀態(tài)。如果目標(biāo)站點(diǎn)是一個(gè)基于域認(rèn)證(例如 IIS上的NTLM)的內(nèi)部網(wǎng)的話,情況同樣如此。幸運(yùn)的是,銀行之類的“嚴(yán)肅”站點(diǎn)卻不會(huì)提供自動(dòng)認(rèn)證——攻擊者也許以為這很“不幸”。
如果該用戶沒(méi)有總處于登錄狀態(tài)的話,那么攻擊者就必須在誘騙用戶瀏覽惡意的HTML之前,首先以某種方式設(shè)法讓受害者先登錄到目標(biāo)站點(diǎn)。對(duì)于那些允許用戶添加內(nèi)容的站點(diǎn)(如論壇)來(lái)說(shuō),這可能很容易:只需添加一個(gè)非常誘人的聲明來(lái)邀請(qǐng)人們查看一個(gè)鏈接即可。然而,很多情況下,攻擊者是無(wú)法在目標(biāo)站點(diǎn)上插入消息的,這樣的話,他就不得不另外想轍了,這時(shí),社交工程恐怕就能派上用場(chǎng)了!比方說(shuō),我們的目標(biāo)站點(diǎn)是一個(gè)名為bank.example.com的銀行,攻擊者想要設(shè)法先讓用戶登錄該銀行,繼而誘騙該用戶瀏覽上面的轉(zhuǎn)賬表單。
為此,攻擊者可以向受害者發(fā)送一封貌似來(lái)自該銀行的電子郵件,如:
大多數(shù)用戶會(huì)都認(rèn)為其中這個(gè)URL指向的是該銀行的,但事實(shí)并非如此。使用@符號(hào)后,這個(gè)URL實(shí)際上是命令瀏覽器以用戶名bank.example.com連接到站點(diǎn)167772161。這個(gè)長(zhǎng)整數(shù)167772161實(shí)際上就是攻擊者的IP地址10.0.0.1,只不過(guò)現(xiàn)在已經(jīng)編碼為一個(gè)32位整數(shù)而已;而check.html則是一個(gè)包含HTML代碼的頁(yè)面,而這些HTML代碼將自動(dòng)提交轉(zhuǎn)帳請(qǐng)求。受害者一旦上鉤,攻擊者就會(huì)發(fā)一筆橫財(cái)。
對(duì)于一些銀行,進(jìn)行一次轉(zhuǎn)帳需要兩個(gè)步驟。首先,您要提供全部轉(zhuǎn)帳細(xì)節(jié):轉(zhuǎn)出方帳戶和轉(zhuǎn)入方帳戶,金額,支付日期等等,所有這些信息都被臨時(shí)存放在該用戶的會(huì)話session中。收集這些信息之后,銀行還有一個(gè)確認(rèn)的步驟,即要求用戶驗(yàn)收這些交易細(xì)節(jié)。請(qǐng)不要認(rèn)為這些銀行在客戶端木馬戰(zhàn)面前會(huì)比那些的銀行更加安全一些。這些站點(diǎn)可能會(huì)像一步式的站點(diǎn)那樣容易被騙:根據(jù)確認(rèn)步驟的實(shí)現(xiàn)方式,設(shè)法讓受害者瀏覽包含多個(gè)框架(frame)的站點(diǎn),每個(gè)框架對(duì)應(yīng)于一個(gè)步驟,如下所示:
文件info.html中有一個(gè)自動(dòng)提交的填有交易細(xì)節(jié)的表單;而文件confirm.html則存放一個(gè)提交確認(rèn)頁(yè)面的腳本,但是要等待適當(dāng)?shù)难舆t,以確保確認(rèn)消息在info.html之后到達(dá)服務(wù)器。至于其他的,我想就沒(méi)有必要再多說(shuō)了吧。
無(wú)論攻擊者選擇什么方法,只要被害者看到由這次轉(zhuǎn)帳引起的頁(yè)面,就會(huì)引起他的懷疑。解決這個(gè)問(wèn)題的方法是把這個(gè)頁(yè)面嵌入一個(gè)小到不會(huì)引起人們注意的框架(frame)中,并在另外一個(gè)框架(frame)中放上一些偽造的信息。如果目標(biāo)站點(diǎn)的某些地方?jīng)]有進(jìn)行HTML輸出過(guò)濾的話,那么還有一個(gè)辦法,那就是轉(zhuǎn)帳一旦完成,就立即通過(guò)跨站腳本把瀏覽器重定向到另一個(gè)頁(yè)面。