CSRF(跨站請求僞造攻擊)漏洞詳解

  Cross-Site Request Forgery(CSRF),中文通常譯做跨站點 請求僞造。常常入選owasp漏洞列表Top10,在當前web漏洞排行中,與XSS和SQL注入並列前三。與前二者相比,CSRF相對來講受到的關注要小不少,可是危害卻很是大。php

  一般狀況下,有三種方法被普遍用來防護CSRF攻擊:驗證token,驗證HTTP請求的Referer,還有驗證XMLHttpRequests裏的自定義header。鑑於種種緣由,這三種方法都不是那麼完美,各有利弊。html

二 CSRF的分類

  在跨站請求僞造(CSRF)攻擊裏面,攻擊者經過用戶的瀏覽器來注入額外的網絡請求,來破壞一個網站會話的完整性。而瀏覽器的安全策略是容許當前頁面發送到任何地址的請求,所以也就意味着當用戶在瀏覽他/她沒法控制的資源時,攻擊者能夠控制頁面的內容來控制瀏覽器發送它精心構造的請求。web

  一、網絡鏈接。例如,若是攻擊者沒法直接訪問防火牆內的資源,他能夠利用防火牆內用戶的瀏覽器間接的對他所想訪問的資源發送網絡請求。甚至還有這樣一種狀況,攻擊者爲了繞過基於IP地址的驗證策略,利用受害者的IP地址來發起他想發起的請求。數據庫

  二、獲知瀏覽器的狀態。當瀏覽器發送請求時,一般狀況下,網絡協議裏包含了瀏覽器的狀態。這其中包括不少,好比cookie,客戶端證書或基於身份驗證的header。所以,當攻擊者藉助瀏覽器向須要上述這些cookie,證書和header等做驗證的站點發送請求的時候,站點則沒法區分真實用戶和攻擊者。跨域

  三、改變瀏覽器的狀態。當攻擊者藉助瀏覽器發起一個請求的時候,瀏覽器也會分析並相應服務端的response。舉個例子,若是服務端的response裏包含有一個Set-Cookie的header,瀏覽器會相應這個Set-Cookie,並修改存儲在本地的cookie。這些改動都會致使很微妙的攻擊,咱們將在第三部分描述。瀏覽器

  做用範圍內的威脅:咱們按照產生危害的大小將此部分分紅三種不一樣的危害模型。安全

  一、論壇可交互的地方。不少網站,好比論壇容許用戶自定義有限種類的內容。舉例來講,一般狀況下,網站容許用戶提交一些被動的如圖像或連接等內容。若是攻擊者讓圖像的  url指向一個惡意的地址,那麼本次網絡請求頗有可能致使CSRF攻擊。這些地方均可以發起請求,但這些請求不能自定義HTTP header,並且必須使用GET方法。儘管HTTP協議規範要求請求不能帶有危害,可是不少網站並不符合這一要求。服務器

  二、Web攻擊者。在這裏web攻擊者的定義是指有本身的獨立域名的惡意代理,好比attacker.com,而且擁有attacker.com的HTTPS證書和web服務器。全部的這些功能只須要花10美圓便可以作到。一旦用戶訪問attacker.com,攻擊者就能夠同時用GET和POST方法發起跨站請求,即爲CSRF攻擊。cookie

  三、網絡攻擊者。這裏的網絡攻擊者指的是能控制用戶網絡鏈接的惡意代理。好比,攻擊者能夠經過控制無線路由器或者DNS服務器來控制用戶的網絡鏈接。這種攻擊比web攻擊須要更多的資源和準備,但咱們認爲這對HTTPS站點也有威脅。由於HTTPS站點只能防禦有源網絡。網絡

  做用範圍外的威脅:下面咱們還列出了一些不在本論文討論範圍的相關危害模型。對這些危害的防護措施能夠與CSRF的防護措施造成很好的互補。

  一、跨站腳本(XSS)。若是攻擊者可以向網站注入腳本,那麼攻擊者就會破壞該網站用戶會話的完整性和保密性。有些XSS攻擊須要發起網絡請求,好比將用戶銀行帳戶裏的錢轉移到攻擊者的帳戶裏,可是一般狀況下,對CSRF的防護並無考慮到這些狀況。考慮到更安全的作法,網站必須實現對XSS和CSRF的同時防護。

  二、惡意軟件。若是攻擊者可以在用戶的電腦上運行惡意軟件,那麼攻擊者就能夠控制用戶的瀏覽器向那些可信的網站注入腳本。這時候基於瀏覽器的防護策略將會失效,由於攻擊者能夠用含有惡意插件的瀏覽器來替換用戶的瀏覽器。

  三、DNS的從新綁定。像CSRF同樣,DNS從新綁定可使用用戶的IP地址來鏈接攻擊者指定的服務器。處在防火牆保護內的服務器或者那些基於IP地址驗證的服務器須要一個對抗DNS從新綁定的防護方案。儘管DNS從新綁定的攻擊和CSRF攻擊的意圖很是類似,可是他們仍是須要各自不一樣的解決方案。一個簡單的解決DNS從新綁定攻擊的方案就是要驗證主機的HTTP請求header,確保包含有預期值。還有一個替代方案就是過濾DNS流量,防止將外部的DNS名稱解析成內部私有地址。

  四、證書錯誤。若是用戶在出現HTTPS證書錯誤的時候還願意繼續點擊訪問,那麼HTTPS可以提供的不少安全保護就沒有意義。有一些安全研究者指出了針對這一種狀況的威害,可是在本文中,咱們假設用戶不會在出現了HTTPS證書錯誤以後繼續點擊訪問。

  五、釣魚。當用戶在訪問釣魚網站的時候,在身份驗證的時候輸入我的信息,釣魚攻擊就發生了。釣魚攻擊現今很是廣泛也頗有效,由於用戶有的時候真的很難區分釣魚網站和真正的網站。

  六、用戶跟蹤。一些合做網站會利用跨站請求來對用戶的瀏覽習慣創建一個關聯行爲庫。大多數瀏覽器都經過組織第三方cookie發送來阻止相似的跟蹤,可是利用掛站請求,瀏覽器的這一特性能夠被繞過。

三 登陸CSRF

  不管是利用瀏覽器的網絡鏈接仍是利用瀏覽器的狀態,大多數對CSRF的討論都集中在能改變服務端狀態的請求上面。儘管CSRF攻擊能經過改變瀏覽器的狀態來對用戶在訪問可信網站時候形成危害,可是對它的重視程度仍是不夠。再登錄CSRF攻擊裏面,攻擊者利用用戶在可信網站的用戶名和密碼來對網站發起一個僞造請求。一旦請求成功,服務器端就會響應一個Set-Cookie的header,瀏覽器接收到之後就會創建一個session cookie,並記錄用戶的登錄狀態。這個session cookie被用做綁定後續的請求,於是也可被攻擊者用來做爲身份驗證。依據不一樣的網站,登錄CSRF攻擊還能夠形成很嚴重的後果。

  搜索記錄:包括谷歌和雅虎等不少搜索引擎容許他們的用戶選擇是否贊成保存他們的搜索記錄,而且爲用戶提供一個接口來查看他們本身的私人搜索記錄。搜索請求裏面包含了用戶的行爲習慣和興趣的一些敏感細節,攻擊者能夠利用這些細節來欺騙用戶,盜竊用戶的身份或者窺探用戶。當攻擊者以用戶身份登錄到搜索引擎裏,就能夠看到用戶的搜索記錄。如圖1. 這樣,用戶的搜索查詢記錄就被存儲到了攻擊者的搜索記錄裏,攻擊者就能夠登錄本身的帳戶隨便查詢用戶的搜索記錄。

  CSRF漏洞說明

圖1. 登錄CSRF攻擊事件的跟蹤圖。受害人訪問攻擊者的網站,攻擊者向谷歌僞造一個跨站點請求的登錄框,形成受害者被攻擊者登錄到谷歌。隨後,受害者使用搜索的時候,搜索記錄就被攻擊者記錄下來。

PayPal:PayPal容許它的用戶相互之間任意轉移資金。轉移資金的時候,用戶要註冊信用卡或者銀行帳戶。攻擊者能夠利用登錄CSRF來發起如下攻擊:

一、受害者訪問了惡意商家的網站,並選擇使用PayPal支付。

二、受害者被重定向到PayPal而且要求登錄他/她的帳戶。

三、網站等待用戶登錄他/她的PayPal帳戶。

四、付款的時候,受害者先是登記本身的信用卡,可是信用卡實際上已經被添加到惡意商家的PayPal帳戶。

iGoogle:用戶能夠經過使用iGoogle來定製本身的谷歌主頁,也包括一些插件。爲了易用性,這些插件是「嵌入到iGoogle的」,這也就意味着他們將影響到iGoogle的安全。一般狀況下,iGoogle在添加新插件的時候,都會詢問用戶作出信任決定。可是攻擊者能夠經過登陸CSRF攻擊來幫助用戶作出決定,從而安裝任意的插件。

一、攻擊者經過用戶的瀏覽器受權安裝一個iGoogle插件(含有惡意腳本),並將插件添加到用戶的定製化iGoogle主頁。

二、攻擊者使用戶登錄谷歌,並開一個到iGoogle的框架。

三、谷歌認爲受害者就是攻擊者,並將攻擊者的插件推送給受害者,並且容許攻擊者在https://www.google.com域下運行腳本。

四、攻擊者如今能夠:(a)在正確的URL頁面構造一個登錄框(b)盜取用戶自動填充的密碼(c)在另外一個窗口等待用戶登錄並讀取document.cookie。

咱們已經將上述漏洞告知了谷歌,他們已經在兩方面來減緩漏洞帶來的危害。首先,谷歌已經棄用內嵌的插件並禁止開發者開發相似的插件,只容許少部分比較受歡迎的內嵌插件。其次,谷歌已經開發了私密token策略來防護登錄CSRF(下面將會討論),可是這個策略只對登錄了的用戶纔有效。咱們預計,谷歌一旦充分測試了他們的防護方案並以爲有效以後,會否定他們的登錄CSRF漏洞。

四 現有的CSRF防護方案

通常網站有三種防護CSRF攻擊的方案。

(1)驗證token值。(2)驗證HTTP頭的Referer。(3)用XMLHttpRequest附加在header裏。以上三種方法都在普遍使用,可是他們的效果都不是那麼的使人滿意。

4.2 Token驗證

在每一個HTTP請求裏附加一部分信息是一個防護CSRF攻擊的很好的方法,由於這樣能夠判斷請求是否已經受權。這個「驗證token」應該不能輕易的被未登陸的用戶猜想出來。若是請求裏面沒有這個驗證token或者token不能匹配的話,服務器應該拒絕這個請求。

Token驗證的方法能夠用來防護登錄CSRF,可是開發者每每會忘記驗證,由於若是沒有登錄,就不能經過session來綁定CSRF token。網站要想用驗證token的方式來防護登錄CSRF攻擊的話,就必須先建立一個「前session」,這樣才能部署CSRF的防護方案,在驗證經過了以後,再建立一個真正的session。

Token的設計。有不少技術能夠生成驗證token。

• session標識符。瀏覽器的cookie存儲方式就是爲了防止不一樣域之間互相訪問cookie。一個廣泛的作法是直接利用用戶的session標識符來做爲驗證token。服務器在處理每個請求時,都將用戶的token與session標識符來匹配。若是攻擊者可以猜想出用戶的token,那麼他就能登陸用戶的帳戶。並且這樣作有個很差的地方在於,偶爾用戶正在瀏覽的內容會發送給第三方,好比經過電子郵件直接上網頁內容上傳到瀏覽器廠商的bug跟蹤數據庫。若是正好這個頁面包含有用戶的session標識符,任何能看到這個頁面的人都能模擬用戶登錄到網站,直到會話過時。

• 獨立session隨機數。與直接使用用戶的session標識符不同的是,當用戶第一次登錄網站的時候,服務器能夠產生一個隨機數並將它存儲在用戶的cookie裏面。對於每個請求,服務器都會將token與存儲在cookie裏的值匹配。例如,普遍使用的Trac問題跟蹤系統就是用的此技術。可是這個方法不能防護主動的網絡攻擊,即便是整個web應用都使用的是HTTPS協議。由於攻擊者可使用他本身的CSRF token來覆蓋來覆蓋這個獨立session隨機數,進而可使用一個匹配的token來僞造一個跨站請求。

• 依賴session隨機數。有一個改進產生隨機數的方法是將用戶的session標識符與CSRF token創建對應關係後存儲在服務端。服務器在處理請求的時候,驗證請求中的token是否與session標識符匹配。這個方法有個很差的地方就是服務端必需要維護一個很大的對應關係表(哈希表)。

• session標識符的HMAC。有一種方法不須要服務端來維護哈希表,就是能夠對用戶的session token作一個加密後用做CSRF 的token。例如, Ruby on Rails的web程序通常都是使用的這種方法,並且他們是使用session標識符的HMAC來做爲CSRF token的。只要全部的網站服務器都共享了HMAC密鑰,那麼每一個服務器均可以驗證請求裏的CSRF token 是否與session標識符匹配。HMAC的特性能確保即便攻擊者知道用戶的CSRF token,也不能推斷出用戶的session標識符。

鑑於有充足的資源,網站均可以使用HMAC方法來防護CSRF攻擊。可是,不少網站和一些CSRF的防護框架(好比NoForge, CSRFx 和CSRFGuard)都不能正確的實現比較隱祕的token防護。一個常見的錯誤就是在處理跨站請求的時候暴露了CSRF token。舉個例子,一個可信的網站在對另外一個網站發起請求的時候附加上了CSRF token,那麼那個網站就能夠對這個可信的網站僞造一個跨站請求。

案例研究:NoForge.NoForge就是使用服務端保存哈希表的方式來驗證用戶的CSRF token。它在全部連接和表單提交的時候會附加一個CSRF token,形成這種技術不太完善的緣由有如下三個:

一、HTML是在瀏覽器裏動態建立的,而不會被從新加上CSRF token。有些網站是在客戶端建立HTML的。好比Gmail, Flickr, 和 Digg都是用JavaScript 來建立表單,而這些表單正是須要CSRF防護措施的。

二、NoForge並無對指向本站和外站的超連接做區分。若是有一個指向外站的超連接,那麼外站能夠用請求裏面獲取到用戶的CSRF token。好比,若是phpBB部署了NoForge,那麼一旦用戶點擊了一個鏈接,鏈接的站點就能夠獲取到用戶的CSRF token,即便NoForge區分了是本站的連接仍是外站的連接,由於Referer 仍是會暴露用戶的CSRF token。

三、NoForge對登錄CSRF並無什麼效果,由於若是用戶已經有了session標識符(登錄了),那麼NoForge只會驗證CSRF token。儘管這種缺陷是能夠修復,可是這也說明了要想正確的實施token驗證策略並非一件很容易的事情。

雖然上述三個緣由都是能夠修復的,可是這些缺陷都說明了要想正確地實施token驗證策略,是很複雜的一件事情。CSRFx 和 CSRFGuard,還有不少網站都說明了這一問題。

4.2 Referer

大多數狀況下,當瀏覽器發起一個HTTP請求,其中的Referer標識了請求是從哪裏發起的。若是HTTP頭裏包含有Referer的時候,咱們能夠區分請求是同域下仍是跨站發起的,由於Referer離標明瞭發起請求的URL。網站也能夠經過判斷有問題的請求是不是同域下發起的來防護CSRF攻擊。

不幸的是,一般Referer會包含有一些敏感信息,可能會侵犯用戶的隱私。好比,Referer能夠顯示用戶對某個私密網站的搜索和查詢。儘管這些內容對私密網站站長來講是好事,由於他們能夠經過這些內容來優化搜索引擎排名,可是一些用戶仍是認爲侵犯了他們的隱私。另外,許多組織也很擔心Referer可能會將內網的一些機密信息泄露出去。

漏洞。從歷史上來看,瀏覽器的一些漏洞使得一些惡意網站有欺騙Referer的價值,尤爲是在使用代理服務器的時候。不少對Referer欺騙的討論都標明瀏覽器容許Referer能夠僞造。Mozilla在Fire-fox 1.0.7裏面已經修復了Referer欺騙的漏洞。目前的IE則還有這方面的漏洞,可是這些漏洞只能影響XMLHttpRequest,而且只能用來僞造Referer跳轉到攻擊者本身的網站。

尺度。若是網站選擇使用Referer來防護CSRF攻擊的話,那麼網站的開發人員就須要決定究竟是使用比較寬鬆仍是比較嚴格的Referer驗證策略。若是採用寬鬆的Referer驗證策略,網站就應該阻止Referer值不對的請求。若是請求裏面沒有Referer,就接收請求。儘管這個方法用的很廣泛,可是它很容易被繞過。由於攻擊者能夠在header裏面去掉Referer。例如,FTP和數據URL發起的請求裏面就不包含Referer。若是使用嚴格的Referer驗證策略,網站還要阻止沒有Referer的請求。這樣作主要是爲了防止惡意網站主動隱藏Referer,但也會帶來兼容性問題,好比會誤殺一部分合法的請求,由於有些瀏覽器和網絡的設置默認就是不含有Referer的。因此說這個度必定要掌握好,不少時候取決於經驗。咱們還會在4.2.1裏討論這個問題。

個案研究:Facebook。縱觀Facebook的大部分網站都是使用token認證的方式來防護CSRF攻擊的。可是,在Facebook的登錄框部分則使用的是寬鬆的Referer驗證策略。這種方法在面對登錄CSRF的攻擊時沒有什麼做用。舉例來講,攻擊者能夠講用戶從http://attacker.com/重定向到ftp://attacker.com/index.html ,而後再對Facebook發起一個跨站的登錄請求。由於請求來自FTP URL,因此大多數瀏覽器都不會在請求裏包含Referer。

4.2.1 實驗

爲了評估嚴格的Referer驗證策略的兼容性,咱們進行了一項實驗來衡量到底有多大機率以及在什麼狀況下,合法的請求裏面不含有Referer。

設計。廣告是一個很方便測量瀏覽器和網絡特徵的渠道,所以咱們能夠利用廣告做爲實驗平臺。在2008年4月5日到4月8日期間,咱們從163,767個獨立IP購買了283,945 個廣告,分別是兩個不一樣的廣告渠道。在渠道A,咱們以每千次展現0.50美圓的價格購買了網絡旗幟廣告,關鍵字爲「火狐」,「遊戲」,「IE」,「視頻」,「YouTube」。在渠道B,咱們以每千次展現5美圓的價格的間隙廣告,關鍵字爲「芭蕾」,「金融「,「花」,「食品」和「園藝」。咱們在每一個廣告渠道上花了100美圓,渠道A有241,483點擊量(146,310個獨立IP),渠道B有42,406點擊量(18,314個獨立IP)。

廣告服務是由咱們實驗室裏的兩臺主機提供,兩個獨立的域名是從不一樣的註冊商處購買。每當顯示廣告時,廣告會在接下來的每一個請求裏面生成一個特定的標識符,並隨機選擇一臺主機做爲主服務器。主服務器經過HTTP或者HTTPS協議將客戶端HTML發送到咱們的服務器,這些HTML能發起一個GET或者POST請求。其中,請求包括提交表單,圖像請求和XMLHttpRequests。請求的順序是隨機的而且跟用戶的操做無關。當廣告經過了瀏覽器的安全策略以後,就向主服務器發起一個同域的請求,同時向次服務器發起一個跨域請求。每一個服務器的成本是400美圓,域名是7美圓,從一個合法的證書頒發機構得到的90天域驗證的HTTPS證書是免費的。服務器根據接收到的網絡請求來記錄請求參數,包括Referer,User-Agent頭,日期,客戶端的C類網絡,會話標識符。服務器還經過DOM API記錄了document.referrer的值,可是不記錄客戶端的IP地址。爲了統計獨立的IP地址,服務器利用一個隨機產生的KEY而不是記錄HMAC的方式,這個KEY會被丟棄。服務器記錄的信息不足以單獨肯定廣告的瀏覽者到底有多少。

倫理。實驗的設計遵照兩個廣告渠道的規則。實驗中的行爲基本上都是web廣告天天的行爲,因此都能正常的從廣告商那裏請求額外的資源,好比圖片,音頻和視頻。儘管咱們的廣告產生的HTTP請求數目遠大於普通的廣告,可是咱們須要的帶寬明顯比一個視頻廣告須要的帶寬要小。咱們的服務器也像廣告商同樣,只記錄他們所記錄的信息。實際上咱們的服務器記錄的信息明顯要比商業的廣告商要少,由於咱們並不記錄客戶端的IP地址。

結果。咱們已經將結果在圖2和圖3裏總結出來了,咱們還發現如下結果只有95%的可信度。

• HTTP方法裏, 跨域請求比同域請求不包含Referer頭的狀況更廣泛,而在POST方法(卡方係數= 2130, p值<0.001) 和GET方法(卡方係數= 2175, p值<0.001) 裏比較,前者不包含Referer頭的狀況更爲廣泛。 • 在不包含Referer頭的統計中,HTTP比HTTPS更爲廣泛,包括跨域POST(卡方係數= 6754, p值<0.001)請求,跨域GET(卡方係數= 6940, p值<0.001)請求,同域POST(卡方係數= 2286, p值<0.001)請求和同域GET請求(卡方係數= 2377, p值<0.001)。 • 在不包含Referer頭的統計中,廣告渠道B全部形式的請求都比A要更廣泛。這些請求形式包括:HTTP跨域POST(卡方係數= 3060, p值<0.001),HTTP同域POST(卡方係數= 6537, p值<0.001),HTTPS跨域POST(卡方係數= 49.13, p值<0.001)和HTTPS同域POST(卡方係數= 44.52, p值<0.001)請求。 • 咱們還統計了自定義的header X-Requested-By(參見4.3節)和Origin(見第5章),X-Requested-By大概有0.029%到0.047%的HTTP POST請求,0.084%到0.112%的HTTP GET請求,0.008%到0.018%的HTTPS POST請求和 0.009%到0.020%的HTTPS GET請求裏不包含有Referer頭。Origin則在與上述相同的請求裏都不包含Referer頭。 CSRF漏洞說明

圖2. 不包含Referer和Referer不正確的請求(283,945 個結果)。x和y分別表明主服務器和次服務器的域名

討論。下面有兩個有力的證據能夠代表在不包含Referer的請求裏,一般是來自網絡(攻擊)而不是瀏覽器。

一、HTTP請求比HTTPS請求不包含Referer更爲廣泛是由於,網絡代理能夠刪除HTTP請求裏的header,可是不能刪除HTTPS請求裏的header。固然,在一些企業的網絡裏,一些HTTPS的終端就是一個網絡代理,這種狀況下代理能夠修改HTTPS請求,可是這種狀況是比較罕見的。

二、瀏覽器在去掉Referer的時候也會去掉document.referrer的值,可是若是Referer是在網絡裏去掉的話,document.referrer卻還在。可是咱們發現,Referer去掉的狀況比document.referrer去掉的狀況要更爲廣泛。

實際上,在實驗中,document.referrer值被去掉主要是由於兩種特殊的瀏覽器:PlayStation 3 瀏覽器不支持document.referrer,Opera去掉document.referrer(可是並不去掉Referer)是爲了跨站HTTPS請求。XMLHttpRequest中的Referer被去掉的比例較高是因爲Firefox 1.0和1.5中的bug引發的。全部的這些結果都代表只有極少數的瀏覽器被配置成不發送Referer。

也有證據代表,Referer被去掉是因爲涉及到隱私問題,當瀏覽器把Referer從網站A發送到網站B時,用戶的隱私也在被暴露,由於網站B能夠經過Referer來收集用戶在網站A的瀏覽行爲。相比之下,在同域下發送Referer則不會引發隱私問題,由於網站徹底能夠經過cookie來收集用戶的隱私(也就是徹底沒有必要經過Referer來收集)。咱們還發現,跨站請求比同站請求要更多的阻止Referer,說明因爲考慮到隱私的問題,因此纔會人爲的阻止Referer發送。

由此,咱們得出兩個主要的結論:

一、經過HTTPS來防護CSRF。在HTTPS請求裏,Referer能夠被用來防護CSRF。爲了實施用Referer來防護CSRF的策略,網站必須拒絕那些沒有Referer的請求,由於攻擊者能夠控制瀏覽器來去掉Referer。而在HTTP裏,網站則不能一味的拒絕沒有Referer的請求,由於考慮到兼容性,可能有至關大一部分 (大約 3–11%)用戶可能就訪問不了網站了。不一樣的是在HTTPS裏,則能夠執行嚴格的Referer驗證策略,由於只有很小的一部分(0.05–0.22%)瀏覽器會去掉Referer。特別須要指出的是,嚴格的Referer驗證策略很是適合用來防護登錄CSRF,由於一般狀況下,登錄請求都是經過HTTPS協議發起的。

二、隱私問題。嚴格的Referer策略是很好的CSRF的防護方案,由於它實施起來很簡單。不幸的是,隱私策略可能會阻止此方案的流行。所以,瀏覽器新的安全性能和新的CSRF防護機制都必需要先解決好隱私問題,才能大規模的部署。

CSRF漏洞說明

圖3. 廣告渠道A中不包含Referer和Referer不正確的請求(241,483 個結果)。Opera阻止了跨站的HTTPS document.referrer,Firefox 1.0和1.5因爲bug在XMLHttpRequest的時候不發送Referer,PlayStation 3(圖中即爲PS)不支持document.referrer。

4.3 自定義HTTP header

咱們也能夠用自定義HTTP頭的方法來防護CSRF攻擊,由於雖然瀏覽器會阻止向外站發送自定義的HTTP頭,可是容許向本站經過XMLHttpRequest的方式發送自定義HTTP頭。好比,prototype.js這個JavaScript庫就是使用這種方法,而且增長了 X-Requested-By頭到XMLHttpRequest裏面 。Google Web Toolkit 也建議開發者用在XMLHttpRequest裏增長一個X-XSRF-Cookie頭的方法來防護CSRF攻擊,其中XMLHttpRequets包含有cookie的值。固然XMLHttpRequets裏面的cookie並不須要用來防護CSRF,由於只須要有頭部分就足夠了。

在使用這種方法來防護CSRF攻擊的時候,網站必須在全部的請求裏使用XMLHttpRequest並附加一個自定義頭(好比X-Requested-By),而且拒絕全部沒有自定義頭的的請求。例如,爲了防護登錄CSRF的攻擊,網站必須經過XMLHttpRequest的方式發送用戶的身份驗證信息到服務器。在咱們的實驗裏,在服務器接收到的請求裏面,大約有99.90–99.99%的請求是含有X-Requested-By頭的,這代表這一方法適用於絕大多數的用戶。

五 建議:Origin字段

爲了防止CSRF的攻擊,咱們建議修改瀏覽器在發送POST請求的時候加上一個Origin字段,這個Origin字段主要是用來標識出最初請求是從哪裏發起的。若是瀏覽器不能肯定源在哪裏,那麼在發送的請求裏面Origin字段的值就爲空。

隱私方面:這種Origin字段的方式比Referer更人性化,由於它尊重了用戶的隱私。

一、Origin字段裏只包含是誰發起的請求,並無其餘信息 (一般狀況下是方案,主機和活動文檔URL的端口)。跟Referer不同的是,Origin字段並無包含涉及到用戶隱私的URL路徑和請求內容,這個尤爲重要。

二、Origin字段只存在於POST請求,而Referer則存在於全部類型的請求。

隨便點擊一個超連接(好比從搜索列表裏或者企業intranet),並不會發送Origin字段,這樣能夠防止敏感信息的之外泄露。

在應對隱私問題方面,Origin字段的方法可能更能迎合用戶的口味。

服務端要作的:用Origin字段的方法來防護CSRF攻擊的時候,網站須要作到如下幾點:

一、在全部能改變狀態的請求裏,包括登錄請求,都必須使用POST方法。對於一些特定的能改變狀態的GET請求必需要拒絕,這是爲了對抗上文中提到過的論壇張貼的那種危害類型。

二、對於那些有Origin字段可是值並非咱們但願的(包括值爲空)請求,服務器要一概拒絕。好比,服務器能夠拒絕一切Origin字段爲外站的請求。

安全性分析:雖然Origin字段的設計很是簡單,可是用它來防護CSRF攻擊能夠起到很好的做用。

一、去掉Origin字段。因爲支持這種方法的瀏覽器在每次POST請求的時候都會帶上源header,那麼網站就能夠經過查看是否存在這種Origin字段來肯定請求是不是由支持這種方法的瀏覽器發起的。這種設計能有效防止攻擊者將一個支持這種方法的瀏覽器改變成不支持這種方法的瀏覽器,由於即便你改變瀏覽器去掉了Origin字段,Origin字段仍是存在,只不過值變爲空了。這跟Referer很不同,由於Referer 只要是在請求裏去掉了,那服務器就探測不到了。

二、DNS從新綁定。在現有的瀏覽器裏面,對於同站的XMLHttpRequests,Origin字段能夠被僞造。只依賴網絡鏈接進行身份驗證的網站應當使用在第2章裏提到的DNS從新綁定的方法,好比驗證header裏的Host字段。在使用Origin字段來防護CSRF攻擊的時候,也須要用到DNS從新綁定的方法,他們是相輔相成的。固然對於在第四章裏提到的CSRF防護方法,也須要用到DNS從新綁定的方法。

三、插件。若是網站根據crossdomain.xml準備接受一個跨站HTTP請求的時候,攻擊者能夠在請求裏用Flash Player來設置Origin字段。在處理跨站請求的時候,token驗證的方法處理的很差,由於token會暴露。爲了應對這些攻擊,網站不該當接受不可信來源的跨站請求。

四、應用。Origin字段跟如下四個用來肯定請求來源的建議很是相似。Origin字段如下四個建議的基礎上統一併改進了,目前已經有幾個組織採用了Origin字段的方法建議。

• Cross-Site XMLHttp Request。Cross-Site XMLHttp Request的方法規定了一個Access-Control-Origin 字段,用來肯定請求來源。這個字段存在於全部的HTTP方法,可是它只在XMLHttpRequests請求的時候纔會帶上。咱們對Origin字段的設想就是來源於這個建議,並且Cross-Site XMLHttp Request工做組已經接受咱們的建議願意將字段統一命名爲Origin。

•XDomainRequest。在Internet Explorer 8 Beta 1裏有XDomainRequest的API,它在發送HTTP請求的時候將Referer裏的路徑和請求內容刪掉了。被縮減後的Referer字段能夠標識請求的來源。咱們的實驗結果代表這種刪減的Referer字段常常會被拒絕,而咱們的Origin字段卻不會。微軟已經發表聲明將會採用咱們的建議將XDomainRequest裏的刪減Referer更改成Origin字段。

• JSONRequest。在JSONRequest這種設計裏,包含有一個Domain字段用來標識發起請求的主機名。相比之下,咱們的Origin字段方法不只包含有主機,還包含請求的方案和端口。JSONRequest規範的設計者已經接受咱們的建議願意將Domain字段更改成Origin字段,以用來防止網絡攻擊。

• Cross-Document Messaging。在HTML5規範裏提出了一個建議,就是創建一個新的瀏覽器API,用來驗證客戶端在HTML文件之間連接。這種設計裏面包含一個不能被覆蓋的origin屬性,若是不是在客戶端的話,在服務端驗證這種origin屬性的過程與咱們驗證origin字段的過程實際上是同樣的。

具體實施:咱們在服務器和瀏覽器端都實現了利用origin字段的方法來防止CSRF攻擊。在瀏覽器端咱們的實現origin字段方式是,在WebKit添加一個8行代碼的補丁,Safari裏有咱們的開源組件,Firefox裏有一個466行代碼的插件。在服務器端咱們實現origin字段的方式是,在ModSecurity應用防火牆裏咱們只用3行代碼,在Apache裏添加一個應用防火牆語言(見圖4)。這些規則在POST請求裏能驗證Host字段和具備合法值的origin字段。在實現這些規則來防護CSRF攻擊的時候,網站並不須要作出什麼改變,並且這些規則還能確保GET請求沒有任何攻擊性(前提是瀏覽器端已經實現了origin字段方法)。

圖4. 在ModSecurity裏實現origin字段方法來防護CSRF攻擊

六 session初始化

在session初始化的時候,登錄CSRF只是其中一個很廣泛的漏洞。在session初始化了以後,web服務器一般會將用戶的身份與session標識符綁定起來。所以有兩種類型的session初始化漏洞,一種是服務器將可信用戶的身份與新初始化的session綁定到了一塊兒,另外一種是服務器將攻擊者的身份與session綁定到了一塊兒。

• 做爲可信用戶的驗證。在某些特定的狀況下,攻擊者可使用一個可預見的session標識符強制網站開啓一個新的session。這一類型的漏洞通常都被稱爲session定位漏洞。當用戶提供他們的身份信息給一個可信網站來驗證後,網站會將用戶的身份與一個可預見的session標識符綁定到一塊兒。攻擊者此時就能夠經過這個session標識符來扮演用戶的身份登陸網站。

• 做爲攻擊者的驗證。攻擊者也能夠經過用戶的瀏覽器強制網站開始一個新的session,而且強制session與攻擊者的身份綁定到一塊兒(第3章已經說明了攻擊是怎麼完成的)。登陸CSRF攻擊只是這一類型中的最簡單漏洞,可是攻擊者還能夠有其餘的方法強制經過用戶的瀏覽器將session與本身綁定到一塊兒。

6.1 HTTP請求

OpenID:像LiveJournal、Movable Type和WordPress等不少網站都在使用OpenID 協議,建議這些可使用自簽名隨機數的方式來對抗回覆攻擊,但不要將OpenID session與用戶的瀏覽器綁定到一塊兒,由於攻擊者能夠強制用戶的瀏覽器初始化一個session而後將session與本身綁定到一塊兒。規範中聲明瞭: return_to 這個URL可能被委託方用來在用戶的驗證請求與驗證答覆之間創建聯繫。可是LiveJournal, Movable Type和WordPress都認爲這不是必須的,也沒有實施它。爲了對抗這種攻擊,在協議初始化的時候委託方應該生成一個新的隨機數,並將它與瀏覽器的cookie存儲到一塊兒,將它包含到return_to參數裏。委託方會將在cookie裏的隨機數與return_to參數裏的隨機數匹配。這種方法其實與token驗證的方法很相似,而且確保了從一開始OpenID 協議的session就能在同一個瀏覽器上完成。

PHP cookieless(不用cookie的)驗證:這種方法被Hushmail 等網站用來防止用戶的電腦上還保留有cookie。Cookieless 驗證方法是將用戶的session標識符存儲在請求的參數裏面。可是這個方法不能將session與用戶的瀏覽器綁定到一塊兒,所以攻擊者能夠強制用戶的瀏覽器初始化一個session與攻擊者綁定到一塊兒。爲了防止這種攻擊,網站必須使用另外的方法將session標識符與用戶的瀏覽器綁定到一塊兒。例如,網站能夠構造一個長時間的frame,其中包含有session標識符。這種方式是經過將session標識符保存在內存裏來將用戶的瀏覽器與session綁定。使用PHP cookieless驗證方法的網站一般也會存在session初始化漏洞,會讓攻擊者能夠模仿一個可信的用戶。固然,相似的session定位漏洞有不少標準的防護方法,例如,當用戶登錄後,網站能夠再次生成一個session標識符。

6.2 Cookie重寫

漏洞。服務器能夠在Set-Cookie字段裏用一個Secure flag方式告訴瀏覽器此cookie只能經過HTTPS協議發送。現金的瀏覽器都支持這個特性,而且在一些對安全性要求比較高的網站,這個特性一般被用來保護session。可是,這個Secure flag並不能保證完整性。攻擊者能夠模仿網站經過HTTP向同一個主機發送Set-Cookie字段,並在主機上設立了cookie。當瀏覽器經過HTTPS向網站發送cookie的時候,網站並無一個機制來肯定cookie是否被攻擊者重寫。若是這個cookie裏面包含有用戶的session標識符,攻擊者就能夠很容易的經過重寫用戶的cookie來發起一個session初始化攻擊。基本上沒有網站可以防護這種攻擊,由於他們須要客戶端提供一個cookie來做完整性驗證。可是,有人建議使用瀏覽器的特性,好比localStorage,它能夠彌補這一不足。換句話說,若是網站聲稱它的應用層session的驗證徹底跟基於cookie的HTTP層的session無關的話,攻擊者能夠在驗證以前就重寫用戶的cookie,而後扮演用戶登錄網站。儘管安全人員不少年前就知道攻擊者能夠重寫cookie,可是瀏覽器廠商並無什麼好的對抗辦法。廠商考慮到了經過拒絕HTTP請求的方式來對抗cookie重寫的攻擊,可是這一作法顯然不太合理。更糟糕的是,這一方法並不能提供cookie的完整性,由於Cookie 字段自己並不能區分cookie 裏是否含有Secure flag。

防護方法。爲了避免改變現有的cookie字段而就能保護cookie的完整性(是否包含有Secure flag),咱們建議瀏覽器能夠在HTTPS請求裏面新加一個Cookie-Integrity字段,專門用來檢測cookie的完整性狀態。這樣也是考慮了兼容之前策略的作法。例如

Cookie: SID=DQAAAHQA…; pref=ac81a9…; TM=1203…

Cookie-Integrity: 0, 2

當cookie被設置成使用HTTPS協議發送的時候,Cookie-Integrity字段能夠在請求裏面用來描述cookie字段的索引。若是請求裏面的cookie都沒有被設置成HTTPS,那麼Cookie-Integrity字段的值就爲空。對Cookie-Integrity字段的完整性的保護與Secure flag能提供的機密是相輔相成的,而且這樣作也具有很好的兼容性,由於服務器會忽略具備沒法識別的header的請求。下面是幾個設計的建議:

帶寬。在每個HTTP請求中添加內容必然會增長全部網絡的延遲,爲了節省帶寬,咱們只在cookie字段裏添加cookie的索引值。還有一個建議作法就是添加一個相似cookie字段的副本,命名爲cookie2。

多樣性。當主機準備創建一個與已有cookie同名的cookie,那麼cookie徹底能夠包含兩個同名的cookie。由於在此種狀況下,也許Cookie-Integrity字段不能根據cookie名來分辨它們,可是咱們能夠在cookie字段裏面經過索引值來區別它們。

Rollback。在HTTPS請求裏面加入Cookie-Integrity字段能夠有效的防止rollback攻擊。 若是沒有Cookie-Integrity字段,而且在不能保證cookie完整性的時候,那麼服務器此時也不能肯定請求裏面的cookie是否具有完整性(假設請求是從一個低版本的主機發出的,即不支持Cookie-Integrity字段)。

同胞域。假設有這樣一種狀況,example.com分別包含有一個可信的和一個不可信的子域,www.example.com 和 users.example.com。在對example.com設置cookie的時候,不可信的子域就能夠注入可信子域的cookie字段。Cookie-Integrity字段並不能防止這種攻擊,可是咱們能夠經過增長一個字段來標識每一個cookie的來源(固然這要取決於對帶寬和複雜性的考慮)。

咱們在Firefox裏用202行JavaScript代碼添加實現了Cookie-Integrity字段,並增長了一個Integrity flag存儲到cookie裏面,主要用來記錄這個cookie是否被設置成使用HTTPS傳輸。

七 總結和建議

CSRF是當今一個被利用的很是普遍的漏洞。不少網站修復了他們的包括登錄CSRF漏洞在內的CSRF漏洞。基於這篇文章中提到的實驗和分析,咱們建議網站在不一樣的狀況下使用不一樣的CSRF防護策略。

• 登錄CSRF。咱們建議使用嚴格的Referer驗證策略來防護登錄CSRF,由於登錄的表單通常都是經過HTTPS發送,在合法請求裏面的Referer都是真實可靠的。若是碰到沒有Referer字段的登錄請求,那麼網站應該直接拒絕以防護這種惡意的修改。

• HTTPS。對於那些專門使用HTTPS協議的網站,好比銀行類,咱們也建議使用嚴格的Referer驗證策略來防護CSRF攻擊。對於那些有特定跨站需求的請求,網站應該創建一份白名單,好比主頁等。

• 第三方內容。若是網站歸入了第三方的內容,好比圖像外鏈和超連接,網站應該使用一個正確的驗證token 的框架,好比 Ruby-on-Rails。若是這樣的一個框架效果很差的話,網站就應該花時間來設計更好的token 驗證策略,能夠用HMAC方法將用戶的session與token 綁定到一塊兒。

對於更長遠的建議,咱們但願能用Origin字段來替代Referer,由於這樣既保留了既有效果,又尊重了用戶的隱私。最終要廢除利用token來防護CSRF的方式,由於這樣網站就能夠更好的保護不管是HTTP仍是HTTPS請求,而不用擔憂token是否會泄露。

將來的工做。若是使用Origin字段的方法來防護CSRF攻擊,網站要注意在處理GET請求的時候不要有什麼反作用。儘管HTTP規範裏已經這樣要求,可是不少網站並無很好的遵照這一要求。讓網站都執行這一要求正是咱們將來的工做重點。

CSRF攻擊還興起了一個變種,即攻擊者在一個可信的網站嵌入一個frame並引誘用戶點擊(點擊劫持)。儘管從咱們的定義上講,這個並不能算是CSRF攻擊,可是他們有一個很類似的地方就在於,攻擊者都是利用用戶的瀏覽器來對他信任的網站發起一個請求。防護這種攻擊的傳統辦法都是frame busting,可是這種方法有個問題就是它依賴JavaScript,而JavaScript頗有可能會被用戶或者攻擊者禁用。在這裏咱們有個建議是,能夠在Origin字段裏添加一些內容用來描述frame的來源,也就是frame裏面的超連接,這樣受信任的網站就能夠根據frame的來源來決定是拒絕仍是接受這個請求。

相關文章
相關標籤/搜索