跨站僞造請求(CSRF)的理解和總結

背景

隨着互聯網的高速發展,信息安全問題已經成爲企業最爲關注的焦點之一,而前端又是引發企業安全問題的高危據點。在移動互聯網時代,前端人員除了傳統的 XSS、CSRF 等安全問題之外,又時常遭遇網絡劫持、非法調用 Hybrid API 等新型安全問題。當然,瀏覽器自身也在不斷在進化和發展,不斷引入 CSP、Same-Site Cookies 等新技術來增強安全性,但是仍存在很多潛在的威脅,這需要前端技術人員不斷進行“查漏補缺”。

最近在解決網站CSRF安全服務漏洞,看了好多文檔,有一下理解和總結:

CSRF攻擊是什麼

CSRF是跨站請求僞造的縮寫,也被稱爲XSRF, 是一種挾制用戶在當前已登錄的Web應用程序上執行非本意的操作的攻擊方法。
跟跨網站腳本(XSS)相比,XSS利用的是用戶對指定網站的信任,CSRF利用的是網站對用戶網頁瀏覽器的信任。
因爲CSRF攻擊利用的是衝着瀏覽器分不清發起請求是不是真正的用戶本人。,也就是說,簡單的身份驗證只能保證請求發自某個用戶的瀏覽器,卻不能保證請求本身是用戶自願發出的。

一個典型的CSRF攻擊有着如下的流程:

  • 受害者登錄a.com,並保留了登錄憑證(Cookie)。
  • 攻擊者引誘受害者訪問了b.com。
  • b.com 向 a.com 發送了一個請求:a.com/act=xx。瀏覽器會默認攜帶a.com的Cookie。
  • a.com接收到請求後,對請求進行驗證,並確認是受害者的憑證,誤以爲是受害者自己發送的請求。
  • a.com以受害者的名義執行了act=xx。
  • 攻擊完成,攻擊者在受害者不知情的情況下,冒充受害者,讓a.com執行了自己定義的操作

接下來有請小明出場~~

小明的悲慘遭遇

這一天,小明同學百無聊賴地刷着Gmail郵件。大部分都是沒營養的通知、驗證碼、聊天記錄之類。但有一封郵件引起了小明的注意:

甩賣比特幣,一個只要998!!

聰明的小明當然知道這種肯定是騙子,但還是抱着好奇的態度點了進去(請勿模仿)。果然,這只是一個什麼都沒有的空白頁面,小明失望的關閉了頁面。一切似乎什麼都沒有發生......

在這平靜的外表之下,黑客的攻擊已然得手。小明的Gmail中,被偷偷設置了一個過濾規則,這個規則使得所有的郵件都會被自動轉發到[email protected]。小明還在繼續刷着郵件,殊不知他的郵件正在一封封地,如脫繮的野馬一般地,持續不斷地向着黑客的郵箱轉發而去。

不久之後的一天,小明發現自己的域名已經被轉讓了。懵懂的小明以爲是域名到期自己忘了續費,直到有一天,對方開出了 $650 的贖回價碼,小明纔開始覺得不太對勁。

小明仔細查了下域名的轉讓,對方是擁有自己的驗證碼的,而域名的驗證碼只存在於自己的郵箱裏面。小明回想起那天奇怪的鏈接,打開後重新查看了“空白頁”的源碼:

<form method="POST" action="https://mail.google.com/mail/h/ewt1jmuj4ddv/?v=prf" enctype="multipart/form-data"> 
    <input type="hidden" name="cf2_emc" value="true"/> 
    <input type="hidden" name="cf2_email" value="[email protected]"/> 
    .....
    <input type="hidden" name="irf" value="on"/> 
    <input type="hidden" name="nvp_bu_cftb" value="Create Filter"/> 
</form> 
<script> 
    document.forms[0].submit();
</script>

這個頁面只要打開,就會向Gmail發送一個post請求。請求中,執行了“Create Filter”命令,將所有的郵件,轉發到“[email protected]”。

小明由於剛剛就登陸了Gmail,所以這個請求發送時,攜帶着小明的登錄憑證(Cookie),Gmail的後臺接收到請求,驗證了確實有小明的登錄憑證,於是成功給小明配置了過濾器。

黑客可以查看小明的所有郵件,包括郵件裏的域名驗證碼等隱私信息。拿到驗證碼之後,黑客就可以要求域名服務商把域名重置給自己。

小明很快打開Gmail,找到了那條過濾器,將其刪除。然而,已經泄露的郵件,已經被轉讓的域名,再也無法挽回了......

以上就是小明的悲慘遭遇。而“點開一個黑客的鏈接,所有郵件都被竊取”這種事情並不是杜撰的,此事件原型是2007年Gmail的CSRF漏洞:

https://www.davidairey.com/google-Gmail-security-hijack/

當然,目前此漏洞已被Gmail修復,請使用Gmail的同學不要慌張。

幾種常見的攻擊類型

  • GET類型的CSRF

GET類型的CSRF利用非常簡單,只需要一個HTTP請求,一般會這樣利用:

 <img src="http://bank.example/withdraw?amount=10000&for=hacker" > 

在受害者訪問含有這個img的頁面後,瀏覽器會自動向http://bank.example/withdraw?account=xiaoming&amount=10000&for=hacker發出一次HTTP請求。bank.example就會收到包含受害者登錄信息的一次跨域請求。

  • POST類型的CSRF

這種類型的CSRF利用起來通常使用的是一個自動提交的表單,如:

 <form action="http://bank.example/withdraw" method=POST>
    <input type="hidden" name="account" value="xiaoming" />
    <input type="hidden" name="amount" value="10000" />
    <input type="hidden" name="for" value="hacker" />
</form>
<script> document.forms[0].submit(); </script> 

訪問該頁面後,表單會自動提交,相當於模擬用戶完成了一次POST操作。

POST類型的攻擊通常比GET要求更加嚴格一點,但仍並不複雜。任何個人網站、博客,被黑客上傳頁面的網站都有可能是發起攻擊的來源,後端接口不能將安全寄託在僅允許POST上面。

  • 鏈接類型的CSRF

鏈接類型的CSRF並不常見,比起其他兩種用戶打開頁面就中招的情況,這種需要用戶點擊鏈接纔會觸發。這種類型通常是在論壇中發佈的圖片中嵌入惡意鏈接,或者以廣告的形式誘導用戶中招,攻擊者通常會以比較誇張的詞語誘騙用戶點擊,例如:

  <a href="http://test.com/csrf/withdraw.php?amount=1000&for=hacker" taget="_blank">
  重磅消息!!
  <a/>

由於之前用戶登錄了信任的網站A,並且保存登錄狀態,只要用戶主動訪問上面的這個PHP頁面,則表示攻擊成功。

CSRF的特點

  • 攻擊一般發起在第三方網站,而不是被攻擊的網站。被攻擊的網站無法防止攻擊發生。
  • 攻擊利用受害者在被攻擊網站的登錄憑證,冒充受害者提交操作;而不是直接竊取數據。
  • 整個過程攻擊者並不能獲取到受害者的登錄憑證,僅僅是“冒用”。
  • 跨站請求可以用各種方式:圖片URL、超鏈接、CORS、Form提交等等。部分請求方式可以直接嵌入在第三方論壇、文章中,難以進行追蹤。

CSRF通常是跨域的,因爲外域通常更容易被攻擊者掌控。但是如果本域下有容易被利用的功能,比如可以發圖和鏈接的論壇和評論區,攻擊可以直接在本域下進行,而且這種攻擊更加危險。

CSRF攻擊基本原理

最簡單的CSRF攻擊

  1. 用戶Alice登錄和訪問某銀行網站A,保留cookie
  2. Alice被某些信息誘導訪問危險網站B。
  3. 危險網站B上有一個<img>標籤:<img src="http://www.examplebank.com/account=Alice&amount=1000&payfor=Badman" >
  4. 這個標籤的src不指向一張圖片,而是一個http請求,這個請求向銀行要求將Alice的1000元轉給Badman,由於Alice的瀏覽器上有cookie,這樣瀏覽器發出的這個請求就能得到響應執行。
  5. 這樣Alice的錢就被偷了。

進階攻擊

危險網站可以僞造一個表單並隱藏,並在自己網站的onload事件中,觸發這個表單的提交事件,就可以改GET攻擊爲POST攻擊

CSRF攻擊的對象與防範思路

我們要防範它,先要知道它的目標,然後設法保護這些目標。
我們要明白,僅僅靠發起CSRF攻擊的話,黑客只能藉助受害者的cookie騙取服務器的信任,但是黑客並不能憑藉拿到cookie,也看不到 cookie的內容。另外,對於服務器返回的結果,由於瀏覽器同源策略的限制,黑客也無法進行解析。
這就告訴我們,我們要保護的對象是那些可以直接產生數據改變的服務,而對於讀取數據的服務,則不需要進行CSRF的保護。
而保護的關鍵,是 在請求中放入黑客所不能僞造的信息

 

防範手段

最基本的手段:涉及敏感操作的請求改爲POST請求

這個方法的確可以防範一些CSRF攻擊,但是對於進階攻擊就無能爲力了——POST請求一樣可以僞造。
所以這個方法不夠安全。只能提高攻擊的門檻。

一般手段

用戶操作限制——驗證碼機制

方法:添加驗證碼來識別是不是用戶主動去發起這個請求,由於一定強度的驗證碼機器無法識別,因此危險網站不能僞造一個完整的請求。
優點:簡單粗暴,低成本,可靠,能防範99.99%的攻擊者。
缺點:對用戶不友好。

請求來源限制——驗證 HTTP Referer 字段

方法:在HTTP請求頭中有一個字段叫Referer,它記錄了請求的來源地址。 服務器需要做的是驗證這個來源地址是否合法,如果是來自一些不受信任的網站,則拒絕響應。
優點:零成本,簡單易實現。
缺點:由於這個方法嚴重依賴瀏覽器自身,因此安全性全看瀏覽器。

  1. 兼容性不好:每個瀏覽器對於Referer的具體實現可能有差別。
  2. 並不一定可靠:在一些古老的垃圾瀏覽器中,Referer可以被篡改。
  3. 對用戶不友好:Referer值會記錄下用戶的訪問來源,有些用戶認爲這樣會侵犯到他們自己的隱私權。因此有些用戶可能會開啓瀏覽器防止跟蹤功能,不提供Referer,從而導致正常用戶請求被拒絕。

 

額外驗證機制——token的使用

方法:使用token來代替驗證碼驗證。由於黑客並不能拿到和看到cookie裏的內容,所以無法僞造一個完整的請求。基本思路如下:

  1. 服務器隨機產生token(比如把cookie hash化生成),存在session中,放在cookie中或者以ajax的形式交給前端。
  2. 前端發請求的時候,解析cookie中的token,放到請求url裏或者請求頭中。
  3. 服務器驗證token,由於黑客無法得到或者僞造token,所以能防範csrf

更進一步的加強手段(不需要session):

  1. 服務器隨機產生token,然後以token爲密鑰散列生成一段密文
  2. token和密文都隨cookie交給前端
  3. 前端發起請求時把密文和token都交給後端
  4. 後端對token和密文進行正向散列驗證,看token能不能生成同樣的密文
  5. 這樣即使黑客拿到了token 也無法拿到密文。

優點:

  1. 安全性:極大地提高了破解成本(當然還是有辦法破解),但是99%的攻擊者看到散列的時候就已經望而生畏了。
  2. 易用性:非常容易實現。
  3. 友好性:對用戶來說十分友好。

缺點:

  1. 性能擔憂:需要hash計算,增加性能上的成本
  2. cookie臃腫:更加依賴網絡的情況
  3. 並不絕對安全:
    1. 一些論壇之類支持用戶自己發表內容,由於系統也會在這個地址後面加上token,這樣黑客可以在自己的網站上得到這個 token,並馬上就可以發動CSRF攻擊。(進一步加強法可以防範,或者驗證鏈接是否是鏈到自己本站,是的就在後面添加 token,如果是通向外網則不加
    2. 其他攻擊方式如XSS攻擊能拿到cookietoken,當然這不在本文的討論範圍之內。

4.對於POST請求,難以將token附在請求中。(可以通過框架和庫解決)

 

曲線救國——在HTTP頭中自定義屬性並驗證

方法:這種方法也是使用token並進行驗證,和上一種方法不同的是把它放到HTTP頭中自定義的屬性裏。

優點:

  1. 這樣解決了上種方法在請求中加入 token 的不便
  2. 通過 XMLHttpRequest 請求的地址不會被記錄到瀏覽器的地址欄,安全性較高

缺點:

  1. 侷限性非常大:XMLHttpRequest請求通常用於Ajax,並非所有的請求都適合用這個類來發起,而且通過該類請求得到的頁面不能被瀏覽器所記錄下,造成不便。
  2. 對於舊網站,要把所有請求都改爲XMLHttpRequest請求,這樣幾乎是要重寫整個網站,這代價無疑是不能接受的。

總結

因爲CSRF攻擊利用的是衝着瀏覽器分不清發起請求是不是真正的用戶本人,所以防範的關鍵在於在請求中放入黑客所不能僞造的信息。從而防止黑客僞造一個完整的請求欺騙服務器。

詳細解決請參考鏈接:https://my.oschina.net/meituantech/blog/2243958

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章