深度理解CSRF攻擊

?做過Web開發(fā)的朋友或多或少都聽說過CSRF攻擊,但未必真的理解,因?yàn)槲以?jīng)也在好長一段時(shí)間里似懂非懂,比如以為CSRF攻擊采用同源策略的限制就可以避免。希望看完本篇文章后能讓您有更深的理解,最好有一種豁然開朗的感覺:)。

1、什么是CSRF攻擊?

????????CSRF,英文全稱Cross-site request forgery。翻譯過來就是“跨站請求偽造”,怎么理解呢?我們先來看一個(gè)例子:

?? ??? ?用戶U首先通過瀏覽器成功登錄了一個(gè)受信任的電商網(wǎng)站A(比如某寶某東),進(jìn)入頁面后做了些日常操作。這時(shí)候因?yàn)槟承┰蛟跊]有關(guān)閉網(wǎng)站A頁面的情況下又打開了一個(gè)新的瀏覽器頁面(一般是通過tab方式打開),訪問了一個(gè)可能不太安全的網(wǎng)站B(不安全為什么還要打開?別問我,問就是你懂的。),然后在網(wǎng)站的誘惑下做了一些操作,比如點(diǎn)了下按鈕什么的。假如開發(fā)網(wǎng)站B的攻擊者曾經(jīng)對網(wǎng)站A非常了解(也許就是網(wǎng)站A曾經(jīng)的高級碼農(nóng)),那么用戶U可能就已經(jīng)中招了。為什么會中招?因?yàn)樵诖蜷_網(wǎng)站B或者說點(diǎn)擊網(wǎng)站B頁面的某個(gè)按鈕的那一刻,很可能就執(zhí)行了類似下面的代碼:

<form action="https://網(wǎng)站A/methodC" method="post">
? ? <input type="hidden" name="amount" value="2000"/>
? ? <input type="hidden" name="account" value="tom"/>
? ? <input type="submit" value="點(diǎn)我就送!"/>
</form>

? ? ? ?這段代碼的意思是通過表單調(diào)用網(wǎng)站A的某個(gè)方法向攻擊者的賬號轉(zhuǎn)了2000元錢。而實(shí)際的攻擊可能更隱蔽,比如使用JS自動完成上述代碼的提交,你完全不知曉。等到你發(fā)現(xiàn)后想追回這筆錢?很遺憾,這個(gè)網(wǎng)站很可能是境外的,即使你知道被轉(zhuǎn)賬戶是誰也無能為力。

2、產(chǎn)生CSRF攻擊的原因?

現(xiàn)在我們從技術(shù)的角度去梳理下CSRF攻擊是如何完成的。

受害用戶登錄了信任網(wǎng)站A,假如網(wǎng)站A在后端的鑒權(quán)是通過cookie-session機(jī)制完成的,那么此時(shí)session內(nèi)容已被傳到了客戶端本地的cookie。

受害用戶沒有關(guān)閉網(wǎng)站A也沒有注銷登錄,而是在同一瀏覽器里打開了網(wǎng)站B,然后觸發(fā)了網(wǎng)站B的某個(gè)操作,惡意代碼被執(zhí)行,受害用戶執(zhí)行了一個(gè)他自己并不知道的操作,連同之前記錄的session內(nèi)容隨cookie一同傳給了網(wǎng)站A。

網(wǎng)站A收到這個(gè)請求,因?yàn)槭盏搅薱ookie的session內(nèi)容,同時(shí)跨站防護(hù)做的不嚴(yán)謹(jǐn),以為是登錄用戶自己的請求操作,正常執(zhí)行,悲劇就這樣發(fā)生了。

見下圖可能更好的理解(引用自什么是CSRF攻擊?如何防御CRSF攻擊? - 知乎):

????????因?yàn)橛脩粼L問的網(wǎng)站A和B是兩個(gè)不同源的網(wǎng)站,而網(wǎng)站B利用了網(wǎng)站A的漏洞進(jìn)行了攻擊,所以這種攻擊被稱為CSRF即跨站請求偽造攻擊。至于什么是同源網(wǎng)站后面會有解釋。

我們來分析下產(chǎn)生CSRF攻擊的必要條件:

用戶執(zhí)行了不合法的操作,這里特指在登錄網(wǎng)站A后不注銷的情況下在同一瀏覽器里打開了不安全網(wǎng)站B頁面。

服務(wù)端采用了cookie-session機(jī)制鑒權(quán)。

服務(wù)端對跨站請求沒有做嚴(yán)謹(jǐn)?shù)姆雷o(hù),認(rèn)為只要收到客戶端發(fā)來的session內(nèi)容就認(rèn)為是登錄用戶的請求操作。

3、如何避免CSRF攻擊?

????????知道了被攻擊的過程和原因,那怎么避免呢?

1從客戶端用戶來說很難避免,因?yàn)橛脩舸蠖鄶?shù)不懂技術(shù),要求他不打開網(wǎng)站B或者登錄A后注銷(清除本地cookie-session)再打開網(wǎng)站B是不現(xiàn)實(shí)的,再說,人家就是想訪問網(wǎng)站B你也管不了啊。既然客戶端無法避免,那我們只能從服務(wù)端來解決。繼續(xù)往后看

2服務(wù)端采用cookie-session機(jī)制鑒權(quán),可以改為非cookie傳遞參數(shù)的鑒權(quán)機(jī)制,比如Header攜帶WT鑒權(quán),從而避免跨站攻擊。

????????這里可能有些朋友會有疑問,瀏覽器傳遞cookie不是有同源策略的限制么?即不同源的網(wǎng)站之間cookie是不能互相訪問的,那么網(wǎng)站B是怎么做到把網(wǎng)站A的cookie數(shù)據(jù)傳到網(wǎng)站A的后端呢?我們來仔細(xì)解讀下瀏覽器的同源策略:

所謂同源,就是指瀏覽器請求的網(wǎng)址有三個(gè)相同就是同源:

協(xié)議相同,例如都是http或https

域名相同,什么是域名相同請自行谷歌或百度

端口號相同

如果非同源,有以下三種操作受到限制:

Cookie、 localStorage等保存在客戶端機(jī)器上的數(shù)據(jù)無法讀??;

DOM無法獲得;例如惡意網(wǎng)站可以通過iframe打開某個(gè)操作界面,如果可以獲取DOM就相當(dāng)于可以獲取整個(gè)操作界面的信息。

AJAX請求不能發(fā)送。

????????但其中有個(gè)特例,即http實(shí)現(xiàn)規(guī)范里表單的提交不受同源策略的限制(說實(shí)話這個(gè)規(guī)定我不是特別理解),這也就解釋了為什么上面的例子中網(wǎng)站B能將網(wǎng)站A的cooike數(shù)據(jù)發(fā)送給網(wǎng)站A,不相信的朋友可以自行寫代碼驗(yàn)證一下,我曾經(jīng)就這在這里誤解了很久。

另外,即使是ajax,可能由于網(wǎng)站A采用了前后端分離的方式部署,即前端域名和后端域名不同源,為了保證前后端數(shù)據(jù)交互,必須解除同源策略的限制。所以在某些網(wǎng)站同源策略的限制實(shí)際沒有產(chǎn)生作用,ajax的請求默認(rèn)允許跨站發(fā)送。(當(dāng)然可以通過在服務(wù)端以白名單的形式解決這個(gè)問題,后面會深入討論。)

????????關(guān)于JWT鑒權(quán)的詳解不是本文的重點(diǎn),網(wǎng)上有大把文章闡述,請自行谷歌或百度,這里不再贅述。

3假如網(wǎng)站A在后端使用cooie-sessionid機(jī)制已經(jīng)根深蒂固,很難重構(gòu),必須使用。那如何解決服務(wù)端對跨站請求做嚴(yán)謹(jǐn)防護(hù)呢?

通過前面的分析我們知道,產(chǎn)生漏洞的根本原因在于網(wǎng)站A出于某些原因無法從根本上執(zhí)行同源策略的限制,無法阻止cookie跨站傳遞,或者說由于前后端分離的部署方式,本身就允許cooike的跨站傳遞。那我們?nèi)绾卧诜?wù)端分辨這個(gè)帶有合法cookie-sessionid的請求是登錄用戶真正發(fā)出的呢?

A、通過頭Referer字段驗(yàn)證

????????瀏覽器請求的header中包含一個(gè)Referer字段,這個(gè)字段可以獲取請求的來源地址。我們可以事先在服務(wù)端建立一個(gè)訪問白名單,如果來源地址不在白名單中,則認(rèn)為是非法請求。

不過這種方法并非絕對安全,Referer 的值是由瀏覽器提供的,每個(gè)瀏覽器對于 Referer 的具體實(shí)現(xiàn)不盡相同,并不能保證瀏覽器自身沒有安全漏洞。某些瀏覽器(比如IE系列老版本),存在篡改其Referer字段的可能。攻擊者只要將Referer的來源地址改為白名單網(wǎng)站地址,CSRF攻擊仍然無法避免。不過現(xiàn)代瀏覽器基本杜絕了這個(gè)安全漏洞,反之存在這個(gè)漏洞的瀏覽器基本絕跡,所以只要網(wǎng)站限制住不安全客戶端瀏覽器的使用,這個(gè)方法基本是可行的。

優(yōu)點(diǎn):實(shí)現(xiàn)簡單對原有系統(tǒng)改變較小,尤其是前端代碼基本不用改動。

缺點(diǎn):不能完全保證安全

B、通過在請求地址中添加token字段驗(yàn)證

????????????????token字段一般是一個(gè)uuid字符串,可以在用戶登錄成功后產(chǎn)生并放于 session 之中同時(shí)回傳給瀏覽器存儲在頁面中。在用戶后續(xù)的請求中在參數(shù)中附帶這個(gè)token,在服務(wù)端收到后續(xù)請求在攔截器中把 session中的token拿出與請求中的 token 進(jìn)行比對,一致則表明是合法用戶請求。

優(yōu)點(diǎn):由于token字段存在于網(wǎng)站A自身的頁面中且每次登錄都是隨機(jī)產(chǎn)生的,攻擊者無法直接獲取,所以這種方法理論上說是絕對安全的。

缺點(diǎn):由于需要在瀏覽器端的所有請求中加上token參數(shù),尤其是以表單提交的代碼,前端改版的工作量較大。

網(wǎng)上還有兩種方法。

????????一種是在 HTTP 頭中增加自定義屬性并驗(yàn)證,類似請求地址token字段驗(yàn)證,這種方法只限于ajax提交的方式,表單提交請求無法實(shí)現(xiàn),局限性太大,所以不推薦。

????????一種采用圖片驗(yàn)證碼的方法。由于對原系統(tǒng)改動量太大且對用戶很不友好,所以這里就不具體介紹了。

????????當(dāng)然,以上兩種方法在特定場合可以作為一種補(bǔ)充方案。

綜上所述,最終解決方案:

服務(wù)端將cookie-session機(jī)制采用類似Header中攜帶JWT參數(shù)鑒權(quán)的解決方案,但其也有缺點(diǎn),具體請自行網(wǎng)上搜索。

服務(wù)端在繼續(xù)使用cookie-session機(jī)制的前提下,如果網(wǎng)站對數(shù)據(jù)安全要求不是特別高則可以采用A方案,否則采用B方案。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容