讓我們一起來(lái)消滅CSRF跨站請(qǐng)求偽造(上)
寫在前面的話
現(xiàn)在已經(jīng)是2017年了,想必大家一定知道什么是CSRF(跨站請(qǐng)求偽造)了,因?yàn)橹瓣P(guān)于這個(gè)話題的討論已經(jīng)有很多了。這種漏洞已經(jīng)存在了很多年,社區(qū)中也有非常詳細(xì)的文檔以及對(duì)應(yīng)的解決方案,目前很多熱門的網(wǎng)站開發(fā)框架基本上或多或少都實(shí)現(xiàn)了相應(yīng)的緩解方案。
那我們?cè)诒鞠盗形恼轮幸懻撌裁茨?請(qǐng)大家先思考以下幾個(gè)因素:
- 遺留應(yīng)用缺少CSRF保護(hù);
- 某些框架的內(nèi)置CSRF防護(hù)機(jī)制存在缺陷;
- 應(yīng)用程序沒(méi)有使用已證明安全的框架保護(hù)機(jī)制;
- 新的應(yīng)用程序沒(méi)有使用提供了CSRF保護(hù)功能的現(xiàn)代框架;
因此,對(duì)于目前的Web應(yīng)用程序來(lái)說(shuō),CSRF仍然是一個(gè)相對(duì)普遍存在的安全漏洞。
在這篇文章中,我們首先會(huì)跟大家深入分析CSRF的工作機(jī)制,以及現(xiàn)代應(yīng)用程序可以采用的安全措施。接下來(lái),我們會(huì)給大家提供一份安全解決方案,同學(xué)們可以將其用于自己所開發(fā)的應(yīng)用程序之中(不需要對(duì)源代碼進(jìn)行任何修改)。最后,我們會(huì)給大家測(cè)試一種針對(duì)cookie的新型擴(kuò)展,如果它能夠成為一種通用標(biāo)準(zhǔn)的話,它將能夠消除絕大多數(shù)場(chǎng)景下的跨站腳本漏洞。除此之外,我們?cè)贕itHub庫(kù)中提供了本系列文章中所要使用到的代碼以及測(cè)試樣例,有需要的同學(xué)可以自行下載。
了解攻擊機(jī)制
簡(jiǎn)而言之,CSRF這種漏洞將允許攻擊者強(qiáng)迫目標(biāo)用戶代表攻擊者發(fā)送HTTP請(qǐng)求。這種攻擊主要發(fā)生在客戶端(例如Web瀏覽器),而在這種場(chǎng)景下目標(biāo)用戶所發(fā)送的應(yīng)用程序信息是完全可信的,因此攻擊者就可以成功實(shí)現(xiàn)攻擊了。對(duì)于這種類型的攻擊,我們需要關(guān)注以下三個(gè)因素:使用不安全的HTTP verb ,Web瀏覽器對(duì)cookie的處理、以及跨站腳本漏洞(XSS)。
HTTP標(biāo)準(zhǔn)將verb主要分成了安全的以及不安全的兩大類。安全的verb(GET、HEAD以及OPTIONS)主要用于只讀操作,使用了這些verb的請(qǐng)求用于返回與被請(qǐng)求資源有關(guān)的信息,并且不會(huì)對(duì)服務(wù)器端產(chǎn)生影響。不安全的verb(POST、PUT、PATCH和DELETE)主要用于對(duì)資源進(jìn)行修改、創(chuàng)建和刪除操作。但不幸的是,一個(gè)HTTP verb本身所要進(jìn)行的操作是可以被忽略或者被篡改的。
導(dǎo)致HTTP verb使用不當(dāng)?shù)闹饕蛟谟跒g覽器對(duì)HTTP標(biāo)準(zhǔn)的支持存在缺陷,這是一種歷史遺留問(wèn)題。在XML HTTP Request(XHR)流行起來(lái)之前,我們幾乎得依靠特定框架和代碼庫(kù)來(lái)使用HTTP verb(除了GET和POST之外)。這種限制導(dǎo)致HTTP verb之間的區(qū)別界限變得十分模糊,雖然僅憑這一點(diǎn)并不能創(chuàng)建出CSRF的攻擊場(chǎng)景,但這也讓針對(duì)CSRF的保護(hù)變得更加難以實(shí)現(xiàn)了。對(duì)CSRF漏洞“幫助”最大的一個(gè)因素,就是瀏覽器處理cookie的方式了。
在設(shè)計(jì)之初,HTTP本身是一種無(wú)狀態(tài)協(xié)議,即一個(gè)請(qǐng)求對(duì)應(yīng)一個(gè)響應(yīng),請(qǐng)求之間不攜帶/交換任何的狀態(tài)信息。為了支持復(fù)雜的Web應(yīng)用程序,cookie就成為了一個(gè)維持相關(guān)HTTP請(qǐng)求之間狀態(tài)的解決方案。瀏覽器的全局Cookie可以跨實(shí)例、窗口和標(biāo)簽進(jìn)行共享,用戶需要依賴于Web瀏覽器來(lái)自動(dòng)化地給每一個(gè)請(qǐng)求發(fā)送cookie。由于cookie是可以在瀏覽器中進(jìn)行訪問(wèn)或修改的,并且缺乏反篡改保護(hù),因此請(qǐng)求狀態(tài)的保存任務(wù)就轉(zhuǎn)移到了服務(wù)器管理會(huì)話的身上。在這種模型下,服務(wù)器端需要生成一個(gè)唯一標(biāo)識(shí)符并將其存儲(chǔ)到cookie中。每一個(gè)瀏覽器在發(fā)送cookie時(shí)都需要發(fā)送這個(gè)唯一標(biāo)識(shí)符,而服務(wù)器端就可以根據(jù)這種標(biāo)識(shí)符來(lái)判斷會(huì)話的有效性了。當(dāng)會(huì)話終止之后,服務(wù)器端會(huì)丟棄這個(gè)標(biāo)識(shí)符,之后使用該標(biāo)識(shí)符的請(qǐng)求都將會(huì)被視為無(wú)效請(qǐng)求。
現(xiàn)在的主要問(wèn)題是,瀏覽器如何去管理cookie。cookie主要由一系列屬性組成,但其中最重要的是Domain屬性。Domain屬性的功能是將cookie限定到某個(gè)匹配domain屬性的特定主機(jī)范圍內(nèi),這是一種用于防止敏感信息(例如會(huì)話識(shí)別符)被惡意網(wǎng)站竊取(會(huì)話固定攻擊)的安全機(jī)制。這里存在的漏洞是domain屬性并不用遵循同源策略(SOP),它只會(huì)對(duì)cookie以及請(qǐng)求中服務(wù)器的domain值進(jìn)行簡(jiǎn)單的對(duì)比。這也就意味著,任何不同源的請(qǐng)求只需要帶有該主機(jī)的cookie,就可以向其發(fā)送請(qǐng)求了。在這種場(chǎng)景下,只有安全的以及不安全的HTTP verb能夠得到正確使用,才能確保這種行為是安全的。關(guān)于同源策略的更多詳細(xì)內(nèi)容,請(qǐng)參考這篇文檔。
最后一個(gè)需要關(guān)心的因素,就是跨站腳本(XSS)漏洞。XSS指的是攻擊者控制JavaScript或HTML來(lái)給目標(biāo)用戶呈現(xiàn)DOM內(nèi)容的能力。如果某個(gè)應(yīng)用程序中存在XSS漏洞的話,那這個(gè)應(yīng)用此時(shí)幾乎就無(wú)法再抵御CSRF攻擊了。如果XSS漏洞存在的話,本文所要介紹的以及目前絕大多數(shù)應(yīng)用程序所依賴的應(yīng)對(duì)措施就完全沒(méi)有用了。
執(zhí)行攻擊
既然我們已經(jīng)了解到了攻擊成功所涉及到的相關(guān)因素,我們就可以繼續(xù)深入了解CSRF的工作機(jī)制了。如果你還沒(méi)有搭建好測(cè)試環(huán)境的話,請(qǐng)現(xiàn)在趕緊按照之前提供的GitHub庫(kù)中的方法(參考README文檔)來(lái)搭建環(huán)境并運(yùn)行樣本。
我們所要討論的主要有以下三種CSRF:
- 資源包含(Resource inclusion)
- Form-based
- XMLHttpRequest
在絕大多數(shù)關(guān)于CSRF的演示樣例或者基礎(chǔ)課程之中,資源包含是這種類型是最常見的。這種類型的CSRF允許攻擊者控制一個(gè)HTML標(biāo)簽中包含的資源,例如圖片、視頻、音頻、對(duì)象、以及腳本等等。如果攻擊者能夠影響頁(yè)面所加載的URL,則任何包含了遠(yuǎn)程資源的標(biāo)簽都將可以被攻擊者所利用。正如之前所說(shuō)的,由于缺乏同源檢測(cè),這種攻擊并不需要XSS,而且任何能夠控制目標(biāo)網(wǎng)站的攻擊者都能夠?qū)崿F(xiàn)攻擊。這種類型的漏洞僅限適用于GET請(qǐng)求,因?yàn)檫@種請(qǐng)求是瀏覽器專門用來(lái)請(qǐng)求資源URL的,而且這種漏洞的限制就在于它要求不當(dāng)使用安全的HTTP verb。
第二種類型是基于表單(form-based)的CSRF,一般出現(xiàn)在安全verb使用正確的情況下。在這種攻擊場(chǎng)景中,攻擊者要自行創(chuàng)建一個(gè)表單并欺騙用戶提交該表單。表單中包含一段能夠強(qiáng)迫瀏覽器提交該表單的JavaScript代碼段,它不僅全部由隱藏元素組成,而且提交速度非???,所以目標(biāo)用戶幾乎無(wú)法察覺(jué)到。由于瀏覽器處理cookie的方式存在問(wèn)題,因此這種表單可以托管在任何一個(gè)網(wǎng)站上,只要用戶用有效的cookie完成了登錄,攻擊就能成功。第二種漏洞配合釣魚攻擊是比較好的。
我們所要討論的最后一種類型即XMLHttpRequest(XHR),而這種情況是比較少見的,因?yàn)槔眠@種漏洞時(shí)所要滿足的條件太多了。由于很多現(xiàn)代Web應(yīng)用程序都依賴于XHR,因此我們需要花很多事件來(lái)構(gòu)建并實(shí)現(xiàn)這種特定的應(yīng)對(duì)措施。由于同源策略的存在,基于XHR的CSRF一般都是通過(guò)XSS Payload的形式來(lái)利用的。如果沒(méi)有跨域資源共享(CORS),XHR將只能被限制于向特定源發(fā)送請(qǐng)求,這樣也就限制了攻擊者托管自己Payload的途徑。這種漏洞的攻擊Payload其實(shí)是一種標(biāo)準(zhǔn)XHR,攻擊者可以想辦法將其注入到目標(biāo)用戶瀏覽器的頁(yè)面DOM中。
總結(jié)
在接下來(lái)的系列文章中,我們將會(huì)給大家介紹如何在真實(shí)的開發(fā)環(huán)境之中部署最有效的CSRF解決方案.