前端——影子殺手篇

zimo發表於2017-10-10

前言

對於一個影子殺手而言,總能殺人於無形。前端也有影子殺手,它總是防不勝防地危害著你的網站

本篇打算介紹一些前端的影子殺手們——XSS和CSRF。或許,你對它恨之入骨;又或者,你運用的得心應手。恨之入骨,可能是因為你的網站被它搞得苦不堪言;得心應手,可能是因為你從事這項工作,每天都在和此類問題打交道。那我們今天就來了解它,防禦它。如果你喜歡我的文章,歡迎評論,歡迎Star~。歡迎關注我的github部落格

正文

注:在開始正文之前,先宣告一下,所有的實驗環境均為本地搭建——DVWA。

影子殺手們,由來已久,幾乎伴隨著整個網際網路的發展。歷史的潮流,總是值得去考究,去深思的。可能在十年之前,這些問題層出不窮;隨著開發者安全意識的提高,總是多多少少可以避免的。那麼,我們就先來看看,今天的第一位主角——XSS。

第一位主角——XSS

記得在學校的時候,玩過CTF,應對類似於XSS等網路漏洞,總是會有固定的套路。今天我們也來了解了解這些套路。

概述

XSS的全名叫做Cross-site Scripting。不知你可否會有個疑問,老外都喜歡將英文縮寫,但是為什麼這個縮寫卻是XSS呢?因為只能怪它來的晚咯,被css搶先一步^_^。不過沒關係,並不阻礙我們記憶它。

XSS是一種程式碼注入類攻擊,它允許攻擊者在其他人的電腦上面執行惡意的指令碼程式碼。往往XSS並不需要攻擊者去直接攻擊受害者的瀏覽器。攻擊者可以利用網站的漏洞,將這一段惡意程式碼提交。然後,通過網站去傳遞給受害者,同時竊取受害者的資訊等。

我們可以先看一個簡單的例子:

或許,你會好奇,我應該怎麼去運用網站的漏洞,那我們先來看一張圖:

comment
comment

這是一個評論框,然後我們可以在其中輸入:

comment
comment

然後,你提交這條資訊,如果該網站沒有做防護(例如:過濾),那麼,你所在的頁面會跳出如下畫面:

xss
xss

看了這個資訊,或許你已經意識到了它的危害。因為如果可以這樣子隨意的執行js指令碼,對於你客戶端的資訊(例如:cookie)將統統被竊取。

回到我們的話題,在看到xss的基本效果之後,你會認為JavaScript是危險的嗎?

其實不然,真正的JavaScript是執行在比較嚴格的環境下面,並不會對作業系統或者其他應用造成傷害。不信的話,你可以開啟控制檯,在裡面隨意嘗試,你會發現你並沒有造成任何危害。那麼,我們所謂的XSS的嚴重性,是吹的嗎?

那就更加不是了。首先,我們要申明的是——何為惡意程式碼?惡意程式碼的叫法,並不是因為它本身是有危害的,而是它的意圖是對使用者有害的。我們可以來看看,何為對使用者有害?例子:

  1. JavaScript對於使用者的私密資訊進行讀取(例如:cookies)。
  2. JavaScript可以通過XMLHttpRequest傳送任意的資訊到任意的伺服器上
  3. JavaScript可以修改當前頁面中的任意DOM元素

這些行為,如果是不善的人所為,那麼,將對使用者造成不可估量的損失。

XSS中的角色扮演

XSS整個流程中,會出現不同的角色。演員表可分為:網站、受害者、攻擊者。

網站,通常是指那些會被受害者訪問的HTML頁面。

受害者,指的是那些訪問網站的普通使用者

攻擊者,則是那些躲在陰暗角落,敲擊著鍵盤的惡意使用者。通常,攻擊者還會具備一臺自己的伺服器,用來接收傳送過來的使用者資訊。

整個流程圖,如下:

xss-process
xss-process

整個流程中,演員都是必須的環節,不然整個攻擊都無法完成。可從圖中看出4個步驟:

  1. 攻擊者選取一個具備漏洞的網站,在其資料庫插入惡意程式碼
  2. 使用者向網站伺服器請求這個被注入的網站
  3. 網站伺服器響應使用者請求,併傳送給使用者已被修改的網站
  4. 使用者完成訪問,同時注入的惡意程式碼執行,將使用者的cookie傳送給攻擊者伺服器

希望你對這幅流程圖多看幾眼,因為它也將會是我們後續防禦XSS的先決條件。之後,我們來看看XSS的分類情況

分類

XSS的目標是在受害者的瀏覽器中執行惡意程式碼。而實現這一目標,往往只有不同的途徑,主要可以分為三種:反射型XSS儲存型XSS基於DOM的XSS

  • 反射型XSS:使用者的惡意程式碼字串來源於受害者的請求,例如,郵件中參雜的惡意連結。
  • 儲存型XSS:使用者的惡意程式碼字串來自於網站的資料庫。通常是我們圖中舉的例子——在評論中注入惡意程式碼,讓受害者進行訪問
  • 基於DOM型XSS:這種攻擊的漏洞主要在客戶端,而非服務端。一般比較少見。

由於儲存型的XSS的流程圖,我們已經在上面看到過了。之後,我們需要來看一看反射型的XSS流程圖,如圖:

xss-reflect
xss-reflect

可以看到流程中,並未向網站的資料庫中插入惡意程式碼,而是由以下4步驟組成:

  1. 攻擊者向受害者傳遞一個網站URL地址
  2. 然後,受害者點選了這個地址,同時會向網站發出請求
  3. 網站響應原先已經存在惡意程式碼的網頁給使用者
  4. 當使用者載入完網頁之後,會向攻擊者的伺服器傳送私密資訊。

這種形式往往是需要使用者進行點選的。

還有一種基於DOM的XSS,平時運用較少,而且攻擊條件較為苛刻。在此不做討論。

我們看完分類之後,對於攻擊的大體流程已經掌握。

接下來的操作平臺,我比較推薦——DVWA。因為目前網上XSS漏洞比較少,主要也是因為開發者的重視,而且網上操作會導致一定的危害,所以在本地搭建開發環境是最好的選擇。

實際操作:

最初,我們需要安裝DVWA,這個教程網上有很多,所以,可以自行百度。

第一步,我們需要將DVWA的安全級別調低,因為不同的安全級別採取的防禦措施不同。

DVWA
DVWA

第二步,我們開始在XSS reflected中進行xss試驗。

第三步,在輸入框中輸入"",如圖:

XSS
XSS

第四步:提交之後,我們即可看到彈窗(這裡提醒一下儘量不要使用chrome,那個瀏覽器會遮蔽這些,最好使用老版本的IE),如圖:

xss
xss

如果你具備後臺伺服器的話,那麼就可以將這個cookie通過請求的形式傳送到伺服器後臺上面,此處就不做演示了。

防禦

既然有人企圖使用這些玩意來危害使用者,那麼,我們這些開發者在開發應用的過程中,自然會有應對之策。不知你還記得上面的攻擊流程圖沒有?如果忘記了,不妨回去看一眼。因為,最好的防禦措施就是截斷攻擊環節中的任意一個環節。

首先,作為一個開發者,必須達成的一點共識是所有的使用者輸入都是不安全的。尤其是類似於XSS這類的注入型漏洞。我們可以通過兩個方式對其進行防禦——編碼驗證

編碼:對於使用者的輸入而言,所輸入的內容只會作為資料,而不是程式碼。

驗證:通過正規表示式等方式,去檢查使用者的輸入中是否帶有敏感字元等。

所以,我們的解決方案可以圍繞上述兩點進行展開:

  1. 輸入檢測
    對使用者輸入的資料進行檢測。對於這些程式碼注入類的漏洞原則上是不相信使用者輸入的資料的。所以,我們要對使用者輸入的資料進行一定程度上的過濾,將輸入資料中的特殊字元與關鍵詞都過濾掉,並且對輸入的長度進行一定的限制。只要開發的人員嚴格檢查每個輸入點,對每個輸入點的資料進行檢測和xss過濾,是可以阻止xss攻擊的。

  2. 輸出編碼
    通過前面xss的原理分析,我們知道造成xss的還有一個原因是應用程式直接將使用者輸入的資料嵌入HTML頁面中了。如果我們對使用者輸入的資料進行編碼,之後在嵌入頁面中,那麼html頁面會將輸入的資料當作是普通的資料進行處理。

  3. Cookie安全
    利用xss攻擊,我們可以輕易的獲取到使用者的cookie資訊。那麼我們需要對使用者的cookie進行一定的處理。首先,我們儘可能減少cookie中敏感資訊的儲存,並且儘量對cookie使用hash演算法多次雜湊存放。合理的使用cookie的httponly的屬性值。這樣可以防止惡意的js程式碼對cookie的呼叫。

  4. 禁用指令碼
    可以在瀏覽器中進行js的安全設定。類似與chrome等瀏覽器都會攔截一些危險的xss操作,例如:想要讀取cookie時,瀏覽器會阻止這個操作,徵求使用者指示,同時提醒使用者此類操作的危害性。

對於XSS而言,我們可以瞭解的內容就到此為止。如果你想要深究,可以看一些網路安全的書籍,或者查閱其他的文章,均可得到詳細的解答。下面我們需要介紹我們的第二位主角——CSRF

第二位主角——CSRF

還記得第一位主角的名字叫什麼嗎?是叫——跨站指令碼攻擊。那麼第二位主角也有一個類似的名字——跨站請求偽造(Cross-site request forgery)。

概述

CSRF 顧名思義,是偽造請求,冒充使用者在站內的正常操作。我們知道,絕大多數網站是通過 cookie 等方式辨識使用者身份(包括使用伺服器端 Session 的網站,因為 Session ID 也是大多儲存在 cookie 裡面的),再予以授權的。所以要偽造使用者的正常操作,最好的方法是通過 XSS 或連結欺騙等途徑,讓使用者在本機(即擁有身份 cookie 的瀏覽器端)發起使用者所不知道的請求。

CSRF這種攻擊方式在2000年已經被國外的安全人員提出,但在國內,直到06年才開始被關注,08年,國內外的多個大型社群和互動網站分別爆出CSRF漏洞,如:NYTimes.com(紐約時報)、Metafilter(一個大型的BLOG網站),YouTube和百度HI......

或許,我們現在對它瞭解的少了,但是網路中的確還留有它的足跡。我們具體的操作就不實際操作了。我們可以來看一下CSRF的原理,如圖(該圖來自一篇知名的部落格,在此註明):

CSRF
CSRF

可以從圖中看到以下步驟:

  1. 首先使用者會登入網站A,之後在通過驗證之後,會由cookie來進行資訊的傳遞
  2. 這時,使用者又訪問了網站B(例如:郵件連結等形式),使用者會在不知情的情況下,利用使用者在網站A的cookie,對網站A傳送第三方請求。
  3. A站點通常不會關注這個訪問是來自使用者或者網站B

分類

CSRF也可會分成兩種形式的攻擊:站內攻擊站外攻擊

CSRF站內型別的漏洞在一定程度上是由於程式設計師濫用$_REQUEST類變數造成的,一些敏感的操作本來是要求使用者從表單提交發起POST請求傳參給程式,但是由於使用了$_REQUEST等變數,程式也接收GET請求傳參,這樣就給攻擊者使用CSRF攻擊創造了條件,一般攻擊者只要把預測好的請求引數放在站內一個貼子或者留言的圖片連結裡,受害者瀏覽了這樣的頁面就會被強迫發起請求。

CSRF站外型別的漏洞其實就是傳統意義上的外部提交資料問題,一般程式設計師會考慮給一些留言評論等的表單加上水印以防止SPAM問題,但是為了使用者的體驗性,一些操作可能沒有做任何限制,所以攻擊者可以先預測好請求的引數,在站外的Web頁面裡編寫javascript指令碼偽造檔案請求或和自動提交的表單來實現GET、POST請求,使用者在會話狀態下點選連結訪問站外的Web頁面,客戶端就被強迫發起請求。

防護

CSRF,對於目前而言攻擊較少,也是因為對於這方面的防禦手段越來越成熟所導致的。下面,我們來看一下如何去防護CSRF的攻擊。

預防CSRF攻擊可以從兩方面入手:

  • 正確使用GET、POST和cookie
  • 在非GET請求的時候新增偽隨機碼

何為正確使用GET和POST呢?拿RESTful API舉例來說,GET是獲取資源,而POST是提交修改資源。那麼我們在定義一個url時,遵循這個規則,就可以保證GET的非使用者請求,無法對伺服器資源進行修改,這樣就可以防止GET的CSRF攻擊。

那麼,你可能會疑惑,要是POST的請求攻擊怎麼辦呢?這就需要從第二方面下手。

增加偽隨機碼的方式,一般可以分為三種:

  • 為每個使用者生成一個cookie token,這樣可以保證在每次表單驗證時附帶上同一個偽隨機碼。這種方式是最簡單的,但是同時也需要保證cookie的安全。往往cookie中的資訊是非常容易被盜取的,所以這種方案在保證沒有XSS的前提下是比較安全的。

  • 每次請求生成驗證碼。這種方法是安全的,但是相對於使用者體驗來說,並不友好

  • 不同表單包含一個不同的token。有興趣可以去了解一下,這種是比較安全的POST請求方式。

小結

由於,現在對於CSRF的攻擊預防比較徹底,一般在沒有XSS的前提下,已經很難進行此類攻擊了。所以真實的實際操作環境並沒有多少。以往主要的攻擊手段還是,通過XSS對於cookie進行盜取,然後通過CSRF使用者資料進行修改。我們可以一個例子來說明最經典的銀行的例子:

如果銀行A允許以GET請求的形式來轉賬,我們這裡大多指的不是實際生活中的,因為實際生活中銀行不可能只用get請求轉賬這麼簡單操作:www.mybank.com/Transfer.ph…

這是危險網站B的程式碼段中有這麼一句:

<img src= http://www.mybank.com/Transfer.php?toBankId=11&money=1000”>複製程式碼

那麼當你再回A銀行時,就會發現你的賬戶上已經少了1000元。

當然,這是假的。

總結

前端安全,一直以來都是被關注的重點物件。我們在瞭解他們的同時,應該注重他們的防護,這就是對使用者的包含。可以是XSS的漏洞,時有發生,BAT等大廠的產品也不例外。今天總結了XSS和CSRF的攻擊與防護,是警醒自己,在以後的開發中多加註意,同時,也希望和你們一起分享。

如果你對我寫的有疑問,可以評論,如我寫的有錯誤,歡迎指正。你喜歡我的部落格,請給我關注Star~呦github部落格

相關文章