安全系列之CSRF初探
前言
安全對于互聯網的從業技術人員來講,一直是接觸或者實際使用掌握比較薄弱的一塊,當然對于那些專項搞安全類的技術人員來講除外。 接下來就來聊聊在互聯網領域中常用的一些安全漏洞類型和一些防范手段,當然針對安全這塊,可能我會選擇作為一個系列議題進行分享,而本文先聊聊安全類型中常見的CSRF, 本文重點圍繞CSRF理論方面的知識進行論述,下一章節會結合自身的平臺項目分享一下安全的一些實踐經驗。
CSRF是什么
首先在介紹CSRF之前,我們先了解清楚,何為CSRF? CSRF全稱為(Cross-site request forgery),中文名稱:跨站請求偽造,常用縮寫為CSRF或者有些地方也稱之為XSRF。
那么它能做什么呢,對大家日常使用倒底有哪些危害的? 你這可以這么理解CSRF攻擊:攻擊者利用CSRF盜用了你的身份,以你的名義發送惡意請求,對服務器來說這個請求是完全合法的, 它的常見攻擊行為如以你名義發送郵件,發消息,盜取你的賬號,從而造成你的個人隱私泄露甚至財產安全。
CSRF攻擊原理
知道了CSRF是什么,那么下面來聊聊,它是的攻擊原理是怎樣的:
- 當用戶打開瀏覽器,訪問受信任網站,如網站A,輸入用戶名和密碼請求登錄網站A;
- 在用戶信息通過驗證后,網站A產生Cookie信息并返回給瀏覽器,此時用戶登錄網站A成功,可以正常發送請求到網站A。
- 用戶未退出網站A之前,在同一瀏覽器中,打開一個TAB頁訪問網站B;
- 網站B接收到用戶請求后,返回一些攻擊性代碼,并發出一個請求要求訪問第三方站點A;
- 瀏覽器在接收到這些攻擊性代碼后,根據網站B的請求,在用戶不知情的情況下攜帶Cookie信息,向網站A發出請求。網站A并不知道該請求其實是由B發起的,所以會根據用戶的Cookie信息以用戶所享有的權限處理該請求,導致來自網站B的惡意代碼被執行。
看到這里,有經驗的人,會馬上總結出,發生CSRF攻擊,至少需要滿足兩個條件:
-
1.登錄受信任網站A,并在本地生成Cookie。
-
2.在不登出A的情況下,訪問危險網站B。
那你可能會問,是不是我只要不滿足其中一項,就可以避免CSRF攻擊了,常規來說,確實如此,但你不能保證以下情況不會發生:
-
1.你不能保證你登錄了一個網站后,不再打開一個tab頁面并訪問另外的網站。
-
2.你不能保證你關閉瀏覽器了后,你本地的Cookie立刻過期,你上次的會話已經結束。(事實上,關閉瀏覽器不能結束一個會話,但大多數人都會錯誤的認為關閉瀏覽器就等于退出登錄/結束會話了)
CSRF攻擊對象
在大體了解了CSRF攻擊原理之后,我們來總結一下,CSRF的攻擊對象是什么,只有明確了它的攻擊對象,那么我們在接下來才知道如何去防御它。
從上面的原理中,我們大概能明白了,CSRF 攻擊是攻擊者借助受害者的 cookie 騙取服務器的信任,但是攻擊者并不能拿到 cookie,也看不到 cookie 的內容。 另外,對于服務器返回的結果,由于瀏覽器同源策略的限制,攻擊者也無法進行解析。因此,攻擊者無法從返回的結果中得到任何東西,他所能做的就是給服務 器發送請求,以執行請求中所描述的命令, 在服務器端直接改變數據的值,而非竊取服務器中的數據。所以,我們要保護的對象是那些可以直接產生數據改變的服務,而對于讀取數據的服務,則不需要進行 CSRF 的保護。 比如銀行系統中轉賬的請求會直接改變賬戶的金額,會遭到 CSRF 攻擊,需要保護。而查詢余額是對金額的讀取操作,不會改變數據,CSRF 攻擊無法解析服務器返回的結果,無需保護。
當前防御 CSRF 的幾種策略
驗證 HTTP Referer 字段
根據 HTTP 協議,在 HTTP 頭中有一個字段叫 Referer,它記錄了該 HTTP 請求的來源地址。 在通常情況下,訪問一個安全受限頁面的請求來自于同一個網站,比如需要訪問 http://bank.example/withdraw?account=test&amount=1000000&for=mikezhou, 用戶必須先登陸 bank.example,然后通過點擊頁面上的按鈕來觸發轉賬事件。這時,該轉帳請求的 Referer 值就會是轉賬按鈕所在的頁面的 URL, 通常是以 bank.example 域名開頭的地址。而如果攻擊者要對銀行網站實施 CSRF 攻擊,他只能在他自己的網站構造請求,當用戶通攻擊者的網站發送請求到銀行時, 該請求的 Referer 是指向攻擊者自己的網站。因此,要防御 CSRF 攻擊,銀行網站只需要對于每一個轉賬請求驗證其 Referer 值,如果是以 bank.example 開頭的域名 ,則說明該請求是來自銀行網站自己的請求,是合法的。如果 Referer 是其他網站的話,則有可能攻擊者的 CSRF 攻擊,拒絕該請求。
優勢:
- 這種方法的顯而易見的好處就是簡單易行,網站的普通開發人員不需要操心 CSRF 的漏洞,只需要在最后給所有安全敏感的請求統一增加一個攔截器來檢查 Referer 的值就可以。特別是對于當前現有的系統,不需要改變當前系統的任何已有代碼和邏輯,沒有風險,非常便捷。
弊端
- 然而,這種方法并非萬無一失。Referer 的值是由瀏覽器提供的,雖然 HTTP 協議上有明確的要求,但是每個瀏覽器對于 Referer 的具體實現可能有差別, 并不能保證瀏覽器自身沒有安全漏洞。使用驗證 Referer 值的方法,就是把安全性都依賴于第三方(即瀏覽器)來保障,從理論上來講,這樣并不安全。 事實上,對于某些瀏覽器,比如 IE6 或 FF2,目前已經有一些方法可以篡改 Referer 值。如果 bank.example 網站支持 IE6 瀏覽器攻擊者完全可以把用戶瀏覽器的 Referer 值設為以 bank.example 域名開頭的地址,這樣就可以通過驗證,從而進行 CSRF 攻擊。 即便是使用最新的瀏覽器,黑客無法篡改 Referer 值,這種方法仍然有問題。因為 Referer 值會記錄下用戶的訪問來源,有些用戶認為這樣會侵犯到他們自己的隱私權,特別是有些組織擔心 Referer 值會把組織內網中的某些信息泄露到外網中。因此,用戶自己可以設置瀏覽器使其在發送請求時不再提供 Referer。當他們正常訪問銀行網站時,網站會因為請求沒有 Referer 值而認為是 CSRF 攻擊,拒絕合法用戶的訪問。
在請求地址中添加 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 的最后加上 ,這樣就把 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基礎驗證方法
-
使用loadrunner(或者http發包模擬器),發送兩次完全相同的請求,檢查服務端返回的應答是否完全一樣,如果完全一樣,則表明存在漏洞。
-
使用loadrunner(或者http發包模擬器),發送http請求,分別設置http頭的refer字段為空和其他網站地址,檢查服務端是否返回了錯誤應答,如果是正確應答,則表明存在漏洞
小結
從上面的章節內容中,我們知道了什么是CSRF,以及它的攻擊原理和一些常用的防御方法,那么下章節將結合一些實際例子介紹一下如何攻防。 在結束之前,小結一下上面的內容:
-
CSRF產生流程:
攻擊者發現CSRF漏洞——構造代碼——發送給受害人——受害人打開——受害人執行代碼——完成攻擊 -
CSRF常用防御方法
1、通過 referer、token 或者 驗證碼 來檢測用戶提交。 2、盡量不要在頁面的鏈接中暴露用戶隱私信息。 3、對于用戶修改刪除等操作最好都使用post 操作 。 4、避免全站通用的cookie,嚴格設置cookie的域
歡迎關注技術公眾號:


浙公網安備 33010602011771號