背景
隨着互聯網的高速發展,信息安全問題已經成爲企業最爲關注的焦點之一,而前端又是引發企業安全問題的高危據點。在移動互聯網時代,前端人員除了傳統的 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!!
聰明的小明當然知道這種肯定是騙子,但還是抱着好奇的態度點了進去(請勿模仿)。果然,這只是一個什麼都沒有的空白頁面,小明失望的關閉了頁面。一切似乎什麼都沒有發生......
不久之後的一天,小明發現自己的域名已經被轉讓了。懵懂的小明以爲是域名到期自己忘了續費,直到有一天,對方開出了 $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攻擊
- 用戶Alice登錄和訪問某銀行網站A,保留
cookie
。 - Alice被某些信息誘導訪問危險網站B。
- 危險網站B上有一個
<img>
標籤:<img src="http://www.examplebank.com/account=Alice&amount=1000&payfor=Badman" >
- 這個標籤的src不指向一張圖片,而是一個http請求,這個請求向銀行要求將Alice的1000元轉給Badman,由於Alice的瀏覽器上有
cookie
,這樣瀏覽器發出的這個請求就能得到響應執行。 - 這樣Alice的錢就被偷了。
進階攻擊
危險網站可以僞造一個表單並隱藏,並在自己網站的onload
事件中,觸發這個表單的提交事件,就可以改GET攻擊爲POST攻擊
CSRF攻擊的對象與防範思路
我們要防範它,先要知道它的目標,然後設法保護這些目標。
我們要明白,僅僅靠發起CSRF攻擊的話,黑客只能藉助受害者的cookie
騙取服務器的信任,但是黑客並不能憑藉拿到cookie
,也看不到 cookie
的內容。另外,對於服務器返回的結果,由於瀏覽器同源策略的限制,黑客也無法進行解析。
這就告訴我們,我們要保護的對象是那些可以直接產生數據改變的服務,而對於讀取數據的服務,則不需要進行CSRF
的保護。
而保護的關鍵,是 在請求中放入黑客所不能僞造的信息
防範手段
最基本的手段:涉及敏感操作的請求改爲POST請求
這個方法的確可以防範一些CSRF
攻擊,但是對於進階攻擊就無能爲力了——POST
請求一樣可以僞造。
所以這個方法不夠安全。只能提高攻擊的門檻。
一般手段
用戶操作限制——驗證碼機制
方法:添加驗證碼來識別是不是用戶主動去發起這個請求,由於一定強度的驗證碼機器無法識別,因此危險網站不能僞造一個完整的請求。
優點:簡單粗暴,低成本,可靠,能防範99.99%的攻擊者。
缺點:對用戶不友好。
請求來源限制——驗證 HTTP Referer 字段
方法:在HTTP
請求頭中有一個字段叫Referer
,它記錄了請求的來源地址。 服務器需要做的是驗證這個來源地址是否合法,如果是來自一些不受信任的網站,則拒絕響應。
優點:零成本,簡單易實現。
缺點:由於這個方法嚴重依賴瀏覽器自身,因此安全性全看瀏覽器。
- 兼容性不好:每個瀏覽器對於
Referer
的具體實現可能有差別。 - 並不一定可靠:在一些古老的垃圾瀏覽器中,
Referer
可以被篡改。 - 對用戶不友好:
Referer
值會記錄下用戶的訪問來源,有些用戶認爲這樣會侵犯到他們自己的隱私權。因此有些用戶可能會開啓瀏覽器防止跟蹤功能,不提供Referer
,從而導致正常用戶請求被拒絕。
額外驗證機制——token的使用
方法:使用token
來代替驗證碼驗證。由於黑客並不能拿到和看到cookie
裏的內容,所以無法僞造一個完整的請求。基本思路如下:
- 服務器隨機產生
token
(比如把cookie
hash化生成),存在session
中,放在cookie
中或者以ajax
的形式交給前端。 - 前端發請求的時候,解析
cookie
中的token
,放到請求url
裏或者請求頭中。 - 服務器驗證
token
,由於黑客無法得到或者僞造token
,所以能防範csrf
更進一步的加強手段(不需要session):
- 服務器隨機產生
token
,然後以token
爲密鑰散列生成一段密文 - 把
token
和密文都隨cookie
交給前端 - 前端發起請求時把密文和
token
都交給後端 - 後端對
token
和密文進行正向散列驗證,看token
能不能生成同樣的密文 - 這樣即使黑客拿到了
token
也無法拿到密文。
優點:
- 安全性:極大地提高了破解成本(當然還是有辦法破解),但是99%的攻擊者看到散列的時候就已經望而生畏了。
- 易用性:非常容易實現。
- 友好性:對用戶來說十分友好。
缺點:
- 性能擔憂:需要
hash
計算,增加性能上的成本 cookie
臃腫:更加依賴網絡的情況- 並不絕對安全:
- 一些論壇之類支持用戶自己發表內容,由於系統也會在這個地址後面加上
token
,這樣黑客可以在自己的網站上得到這個token
,並馬上就可以發動CSRF攻擊。(進一步加強法可以防範,或者驗證鏈接是否是鏈到自己本站,是的就在後面添加token
,如果是通向外網則不加 - 其他攻擊方式如XSS攻擊能拿到
cookie
和token
,當然這不在本文的討論範圍之內。
- 一些論壇之類支持用戶自己發表內容,由於系統也會在這個地址後面加上
4.對於POST請求,難以將token
附在請求中。(可以通過框架和庫解決)
曲線救國——在HTTP頭中自定義屬性並驗證
方法:這種方法也是使用token並進行驗證,和上一種方法不同的是把它放到HTTP頭中自定義的屬性裏。
優點:
- 這樣解決了上種方法在請求中加入 token 的不便
- 通過 XMLHttpRequest 請求的地址不會被記錄到瀏覽器的地址欄,安全性較高
缺點:
- 侷限性非常大:XMLHttpRequest請求通常用於Ajax,並非所有的請求都適合用這個類來發起,而且通過該類請求得到的頁面不能被瀏覽器所記錄下,造成不便。
- 對於舊網站,要把所有請求都改爲XMLHttpRequest請求,這樣幾乎是要重寫整個網站,這代價無疑是不能接受的。