Web安全 - CSRF漏洞

Cross-Site Request Forgery

1、原理

CSRF跨站請求僞造:攻擊者盜用了合法用戶的身份,以合法用戶的名義發送惡意請求,對服務器來講這個請求是徹底合法的,可是卻完成了攻擊者所指望的操做,好比以合法用戶的名義發送郵件、發消息,添加系統管理員,甚至於購買商品、虛擬貨幣轉帳等。 程序員

詳細過程:瀏覽器

其中Web A爲存在CSRF漏洞的網站,Web B爲攻擊者構建的惡意網站,User 1爲Web A網站的合法用戶。安全

  1. 用戶1打開瀏覽器,訪問受信任網站A,輸入用戶名和密碼請求登陸網站A;
  2. 在用戶信息經過驗證後,網站A產生Cookie信息並返回給瀏覽器,此時用戶登陸網站A成功,能夠正常發送請求到網站A;
  3. 用戶未退出網站A以前,在同一瀏覽器中,打開一個TAB頁訪問網站B;
  4. 網站B接收到用戶請求後,返回一些攻擊性代碼,併發出一個請求要求訪問第三方站點A;
  5. 瀏覽器在接收到這些攻擊性代碼後,根據網站B的請求,在用戶不知情的狀況下攜帶Cookie信息,向網站A發出請求。網站A並不知道該請求實際上是由B發起的,因此會根據用戶1的Cookie信息以用戶1的權限處理該請求,致使來自網站B的惡意代碼被執行。

CSRF其實是利用站點對用戶的信任。服務器

2、攻擊

CSRF攻擊能夠在受害者絕不知情的狀況下以受害者名義僞造請求發送給受攻擊站點,從而在並未受權的狀況下執行在權限保護之下的操做。session

好比說,受害者Bob在銀行有一筆存款,經過對銀行的網站發送請求http://bank.example/withdraw?account=alen&amount=100&for=alen2可使alen把100的存款轉到alen2的帳號下。一般狀況下,該請求發送到網站後,服務器會先驗證該請求是否來自一個合法的Session,而且該Session的用戶Alen已經成功登錄。黑客Hack本身在該銀行也有帳戶,他知道上文中的URL能夠把錢進行轉賬操做。Hack能夠本身發送一個請求給銀行:http://bank.example/withdraw?account=alen&amount=100&for=Hack。可是這個請求來自Hack而非Alen,他不能經過安全認證,所以該請求不會起做用。併發

這時,Hack想到使用CSRF的攻擊方式,他先本身作一個網站,在網站中放入以下代碼: src="http://bank.example/withdraw?account=alen&amount=100&for=Hack",而且經過廣告等誘使Alen來訪問他的網站。當Alen訪問該網站時,上述URL就會從Alen的瀏覽器發向銀行,而這個請求會附帶Alen瀏覽器中的Cookie一塊兒發向銀行服務器。大多數狀況下,該請求會失敗,由於他要求Alen的認證信息。可是,若是Alen當時恰巧訪問他的銀行後不久,他的瀏覽器與銀行網站之間的Session還沒有過時,瀏覽器的Cookie之中含有的認證信息。這時,悲劇發生了,這個URL請求就會獲得響應,錢將從Alen的帳號轉移到Hack的帳號,而Alen當時絕不知情。等之後Alen發現帳戶錢少了,即便他去銀行查詢日誌,他也只能發現確實有一個來自於他本人的合法請求轉移了資金,沒有任何被攻擊的痕跡。而Hack則能夠拿到錢後逍遙法外。異步

3、防護

1. 驗證HTTP Referer字段

根據HTTP協議,在HTTP頭中有一個Referer字段,它記錄了該HTTP請求的來源地址。在一般狀況下,訪問一個安全受限頁面的請求來自於同一個網站,好比須要訪問http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory,用戶必須先登錄bank.example,而後經過點擊頁面上的按鈕來觸發轉帳事件。這時,該轉賬請求的Referer值就會是轉帳按鈕所在的頁面的URL,一般是以 bank.example域名開頭的地址。而若是黑客要對銀行網站實施CSRF攻擊,他只能在他本身的網站構造請求,當用戶經過黑客的網站發送請求到銀行時,該請求的Referer是指向黑客本身的網站。所以,要防護 CSRF攻擊,銀行網站只須要對於每個轉帳請求驗證其Referer值,若是是以bank.example開頭的域名,則說明該請求是來自銀行網站本身的請求,是合法的。若是Referer是其餘網站的話,則有多是黑客的CSRF攻擊,拒絕該請求。網站

這種方法的顯而易見的好處就是簡單易行,網站的普通開發人員不須要操心CSRF的漏洞,只須要在最後給全部安全敏感的請求統一增長一個攔截器來檢查Referer的值就能夠。特別是對於當前現有的系統,不須要改變當前系統的任何已有代碼和邏輯,沒有風險,很是便捷。編碼

然而,這種方法並不是萬無一失。Referer的值是由瀏覽器提供的,雖然HTTP協議上有明確的要求,可是每一個瀏覽器對於Referer的具體實現可能有差異,並不能保證瀏覽器自身沒有安全漏洞。使用驗證Referer值的方法,就是把安全性都依賴於第三方(即瀏覽器)來保障,從理論上來說,這樣並不安全。事實上,對於某些瀏覽器,好比IE6,目前已經有一些方法能夠篡改Referer值。若是bank.example網站支持IE6瀏覽器,黑客徹底能夠把用戶瀏覽器的Referer值設爲以bank.example域名開頭的地址,這樣就能夠經過驗證,從而進行CSRF攻擊。url

即使是使用最新的瀏覽器,黑客沒法篡改Referer值,這種方法仍然有問題。由於Referer值會記錄下用戶的訪問來源,有些用戶認爲這樣會侵犯到他們本身的隱私權,特別是有些組織擔憂Referer值會把組織內網中的某些信息泄露到外網中。所以,用戶本身能夠設置瀏覽器使其在發送請求時再也不提供Referer。當他們正常訪問銀行網站時,網站會由於請求沒有Referer值而認爲是CSRF攻擊,拒絕合法用戶的訪問。

2. 在請求地址中添加token並驗證

CSRF攻擊之因此可以成功,是由於黑客能夠徹底僞造用戶的請求,該請求中全部的用戶驗證信息都是存在於Cookie中,所以黑客能夠在不知道這些驗證信息的狀況下直接利用用戶本身的Cookie來經過安全驗證。要抵禦CSRF,關鍵在於在請求中放入黑客所不能僞造的信息,而且該信息不存在於Cookie之中。能夠在HTTP請求中以參數的形式加入一個隨機產生的token,並在服務器端創建一個攔截器來驗證這個token,若是請求中沒有token或者token內容不正確,則認爲可能 CSRF攻擊而拒絕該請求。

這種方法要比檢查Referer要安全一些,token能夠在用戶登錄後產生並放於session之中,而後在每次請求時把token從session中拿出,與請求中的token進行比對,但這種方法的難點在於如何把token以參數的形式加入請求。對於GET請求,token將附在請求地址以後,這樣URL就變成http://url?csrftoken=tokenvalue。而對於POST請求來講,要在form的最後加上<input type=」hidden」 name=」csrftoken」 value=」tokenvalue」/>,這樣就把token以參數的形式加入請求了。可是,在一個網站中,能夠接受請求的地方很是多,要對於每個請求都加上token是很麻煩的,而且很容易漏掉,一般使用的方法就是在每次頁面加載時,使用JavaScript遍歷整個Dom樹,對於Dom中全部的a和 form標籤後加入token。這樣能夠解決大部分的請求,可是對於在頁面加載以後動態生成的HTML代碼,這種方法就沒有做用,還須要程序員在編碼時手動添加token。

該方法還有一個缺點是難以保證token自己的安全。特別是在一些論壇之類支持用戶本身發表內容的網站,黑客能夠在上面發佈本身我的網站的地址。因爲系統也會在這個地址後面加上token,黑客能夠在本身的網站上獲得這個token,並立刻就能夠發動CSRF攻擊。爲了不這一點,系統能夠在添加token的時候增長一個判斷,若是這個連接是鏈到本身本站的,就在後面添加token,若是是通向外網則不加。不過,即便這個csrftoken不以參數的形式附加在請求之中,黑客的網站也一樣能夠經過Referer來獲得這個token值以發動CSRF攻擊。這也是一些用戶喜歡手動關閉瀏覽器Referer功能的緣由.

3. 在HTTP頭中自定義屬性並驗證

這種方法也是使用token並進行驗證,和上一種方法不一樣的是,這裏並非把token以參數的形式置於HTTP請求之中,而是把它放到 HTTP 頭中自定義的屬性裏。經過XML HTTP Request這個類,能夠一次性給全部該類請求加上csrftoken這個HTTP頭屬性,並把token值放入其中。這樣解決了上種方法在請求中加入token的不便,同時,經過XML HTTP Request請求的地址不會被記錄到瀏覽器的地址欄,也不用擔憂token會透過Referer泄露到其餘網站中去。

然而這種方法的侷限性很是大。XML Http Request請求一般用於Ajax方法中對於頁面局部的異步刷新,並不是全部的請求都適合用這個類來發起,並且經過該類請求獲得的頁面不能被瀏覽器所記錄下,從而進行前進,後退,刷新,收藏等操做,給用戶帶來不便。另外,對於沒有進行CSRF防禦的遺留系統來講,要採用這種方法來進行防禦,要把全部請求都改XML Http Request請求,這樣幾乎是要重寫整個網站,這代價無疑是不能接受的。

相關文章
相關標籤/搜索