CSRF攻擊與防御,Web安全的第一防線
跨站請求偽造,也被稱為“OneClick Attack”或者Session Riding,通常縮寫為CSRF或者XSRF,是一種對網站的惡意利用。
一、CSRF介紹 CSRF(Cross-site request forgery) 跨站請求偽造,也被稱為“OneClick Attack”或者Session Riding,通常縮寫為CSRF或者XSRF,是一種對網站的惡意利用。
上圖為CSRF攻擊的一個簡單模型,用戶訪問惡意網站B,惡意網站B返回給用戶的HTTP信息中要求用戶訪問網站A,而由于用戶和網站A之間可能已經有信任關系導致這個請求就像用戶真實發送的一樣會被執行。
二、CSRF攻擊的危害 攻擊者盜用了你的身份,以你的名義發送惡意請求,對服務器來說這個請求是完全合法的,但是卻完成了攻擊者所期望的一個操作,比如以你的名義發送郵件、發消息,盜取你的賬號,添加系統管理員,甚至于購買商品、虛擬貨幣轉賬等。 如果CSRF發送的垃圾信息還帶有蠕蟲鏈接的話,那些接收到這些有害信息的好友萬一打開私信中的連接就也成為了有害信息的散播著,這樣數以萬計的用戶被竊取了資料種植了木馬。整個網站的應用就可能在瞬間奔潰,用戶投訴,用戶流失,公司聲譽一落千丈甚至面臨倒閉。曾經在MSN上,一個美國的19歲的小伙子Samy利用css的background漏洞幾小時內讓100多萬用戶成功的感染了他的蠕蟲,雖然這個蠕蟲并沒有破壞整個應用,只是在每一個用戶的簽名后面都增加了一句“Samy 是我的偶像”,但是一旦這些漏洞被惡意用戶利用,后果將不堪設想,同樣的事情也曾經發生在新浪微博上面。 如下:其中Web A為存在CSRF漏洞的網站,Web B為攻擊者構建的惡意網站,User C為Web A網站的合法用戶。
三、CSRF攻擊原理及過程
1 、用戶C打開瀏覽器,訪問受信任網站A,輸入用戶名和密碼請求登錄網站A;
2、在用戶信息通過驗證后,網站A產生Cookie信息并返回給瀏覽器,此時用戶登錄網站A成功,可以正常發送請求到網站A;
3、用戶未退出網站A之前,在同一瀏覽器中,打開一個TAB頁訪問網站B;
4、網站B接收到用戶請求后,返回一些攻擊性代碼,并發出一個請求要求訪問第三方站點A;
5、瀏覽器在接收到這些攻擊性代碼后,根據網站B的請求,在用戶不知情的情況下攜帶Cookie信息,向網站A發出請求。網站A并不知道該請求其實是由B發起的,所以會根據用戶C的Cookie信息以C的權限處理該請求,導致來自網站B的惡意代碼被執行。 舉例: 簡單版: 假如博客園有個加關注的GET接口,blogUserGuid參數很明顯是關注人Id,如下:
那我只需要在我的一篇博文內容里面寫一個img標簽:
那么只要有人打開我這篇博文,那就會自動關注我。 升級版: 假如博客園還是有個加關注的接口,不過已經限制了只獲取POST請求的數據。這個時候就做一個第三方的頁面,但里面包含form提交代碼,然后通過QQ、郵箱等社交工具傳播,誘惑用戶去打開,那打開過博客園的用戶就中招了。 在說例子之前要糾正一個iframe問題,有人會直接在第三方頁面這樣寫。如下:
這樣是用問題的,由于同源策略的原因,iframe內容根本加載不出來,所以里面form提交當然不會執行。 PS:我嘗試了chrome、IE11、Firefox,情況都是這樣。 所以可以用嵌多一層頁面方式解決,如下: 第一個展示頁面(test):
第二個隱藏頁面(test2):

這樣就可以解決了,有人會問為什么要加多一層iframe,因為不嵌iframe頁面會重定向,這樣就降低了攻擊的隱蔽性。另外我們test頁面不使用XMLHTTPRequest發送POST請求,是因為有跨域的問題,而form可以跨域post數據。 進階版: 假如博客園還是有個加關注的接口,已經限制POST,但博文內容是直接貼進HTML(未過濾),那就遭受XSS攻擊。那么就可以直接把上面代碼嵌入博文,那么只要有人打開我這篇博文,還是會自動關注我,這組合攻擊方式稱為XSRF。 四、CSRF漏洞檢測 檢測CSRF漏洞是一項比較繁瑣的工作,最簡單的方法就是抓取一個正常請求的數據包,去掉Referer字段后再重新提交,如果該提交還有效,那么基本上可以確定存在CSRF漏洞。 隨著對CSRF漏洞研究的不斷深入,不斷涌現出一些專門針對CSRF漏洞進行檢測的工具,如CSRFTester,CSRF Request Builder。 以CSRFTester工具為例,CSRF漏洞檢測工具的測試原理如下: 使用CSRFTester進行測試時,首先需要抓取我們在瀏覽器中訪問過的所有鏈接以及所有的表單等信息,然后通過在CSRFTester中修改相應的表單等信息,重新提交,這相當于一次偽造客戶端請求。如果修改后的測試請求成功被網站服務器接受,則說明存在CSRF漏洞,當然此款工具也可以被用來進行CSRF攻擊。 五、CSRF漏洞防御 目前防御 CSRF 攻擊主要有三種策略:驗證 HTTP Referer 字段;在請求地址中添加 token 并驗證;在 HTTP 頭中自定義屬性并驗證。
1、盡量使用POST,限制GET GET接口太容易被拿來做CSRF攻擊,看第一個示例就知道,只要構造一個img標簽,而img標簽又是不能過濾的數據。 接口最好限制為POST使用,GET則無效,降低攻擊風險。 當然POST并不是萬無一失,攻擊者只要構造一個form就可以,但需要在第三方頁面做,這樣就增加暴露的可能性。
2、瀏覽器Cookie策略 IE6、7、8、Safari會默認攔截第三方本地Cookie(Third-party Cookie)的發送。 但是Firefox2、3、Opera、Chrome、Android等不會攔截,所以通過瀏覽器Cookie策略來防御CSRF攻擊不靠譜,只能說是降低了風險。 PS:Cookie分為兩種 Session Cookie(在瀏覽器關閉后,就會失效,保存到內存里), Third-party Cookie(即只有到了Exprie時間后才會失效的Cookie,這種Cookie會保存到本地)。 PS:另外如果網站返回HTTP頭包含P3P Header,那么將允許瀏覽器發送第三方Cookie。
、加驗證碼 驗證碼,強制用戶必須與應用進行交互,才能完成最終請求。在通常情況下,驗證碼能很好遏制CSRF攻擊。 但是出于用戶體驗考慮,網站不能給所有的操作都加上驗證碼。 因此驗證碼只能作為一種輔助手段,不能作為主要解決方案。
4、Referer Check Referer Check在Web最常見的應用就是“防止圖片盜鏈”。 同理,Referer Check也可以被用于檢查請求是否來自合法的“源”(Referer值是否是指定頁面,或者網站的域),如果都不是,那么就極可能是CSRF攻擊。 但是因為服務器并不是什么時候都能取到Referer,所以也無法作為CSRF防御的主要手段。 但是用Referer Check來監控CSRF攻擊的發生,倒是一種可行的方法。
5 、Anti CSRF Token 現在業界對CSRF的防御,一致的做法是使用一個Token(Anti CSRF Token)。 例子:
- 用戶訪問某個表單頁面。
- 服務端生成一個Token,放在用戶的Session中,或者瀏覽器的Cookie中。
- 在頁面表單附帶上Token參數。
- 用戶提交請求后, 服務端驗證表單中的Token是否與用戶Session(或Cookies)中的Token一致,一致為合法請求,不是則非法請求。
這個Token的值必須是隨機的,不可預測的。由于Token的存在,攻擊者無法再構造一個帶有合法Token的請求實施CSRF攻擊。另外使用Token時應注意Token的保密性,盡量把敏感操作由GET改為POST,以form或AJAX形式提交,避免Token泄露。 注意: CSRF的Token僅僅用于對抗CSRF攻擊。當網站同時存在XSS漏洞時候,那這個方案也是空談。 所以XSS帶來的問題,應該使用XSS的防御方案予以解決。 特別是在一些論壇之類支持用戶自己發表內容的網站,黑客可以在上面發布自己個人網站的地址。由于系統也會在這個地址后面加上 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 請求,這樣幾乎是要重寫整個網站,這代價無疑是不能接受的。
六、最后聊聊XSS 惡意攻擊者往Web頁面里插入惡意Script代碼,當用戶瀏覽該頁之時,嵌入其中Web里面的Script代碼會被執行,從而達到惡意攻擊用戶的目的。
XSS攻擊分成兩類來自內部的攻擊:主要指的是利用程序自身的漏洞,構造跨站語句,如:dvbbs的showerror.asp存在的跨站漏洞。
- 來自外部的攻擊:主要指自己構造XSS跨站漏洞網頁或者尋找非目標機以外的有跨站漏洞的網頁。如當我們要滲透一個站點,我們自己構造一個有跨站漏洞的網頁,然后構造跨站語句,通過結合其它技術,如社會工程學等,欺騙目標服務器的管理員打開。
- XSS分為:存儲型和反射型存儲型XSS:存儲型XSS,持久化,代碼是存儲在服務器中的,如在個人信息或發表文章等地方,加入代碼,如果沒有過濾或過濾不嚴,那么這些代碼將儲存到服務器中,用戶訪問該頁面的時候觸發代碼執行。這種XSS比較危險,容易造成蠕蟲,盜竊cookie(雖然還有種DOM型XSS,但是也還是包括在存儲型XSS內)。
- 反射型XSS:非持久化,需要欺騙用戶自己去點擊鏈接才能觸發XSS代碼(服務器中沒有這樣的頁面和內容),一般容易出現在搜索頁面。