跨站腳本攻擊(XSS)已經(jīng)不是什么新鮮的話題了,甚至很多大公司也為此吃盡苦頭。最簡單直接的防范方法,就是不允許任何html標(biāo)簽輸入,對用戶輸入進(jìn)行編碼(htmlencode)。
但是如果想用戶輸入支持一些格式,怎么辦?一種辦法就是很多論壇采用的BB Code的方法。使用特定的標(biāo)簽代替一些格式。比如:[B]表示粗體,等等。但是,BB Code這種形式并不被廣泛接受,它的表現(xiàn)力實(shí)在太差了,而且并不是標(biāo)準(zhǔn)格式。
為了讓用戶的輸入更具表現(xiàn)力,涌現(xiàn)了大量的Html編輯器控件,著名的有FCKEditor,F(xiàn)reeTextBox,Rich TextBox,Cute Editor,TinyMCE等等。比如,博客園的后臺發(fā)隨筆就支持Cute Editor和TinyMCE,我個(gè)人比較喜歡Cute Editor,功能強(qiáng)大,性能不錯(cuò),而且容易定制。
使用這些Html編輯器控件的潛在危險(xiǎn),是用戶可能會輸入一些危險(xiǎn)字符,注入到網(wǎng)站中,形成XSS攻擊。一個(gè)最簡單的輸入就是:
<javascript>alert('xss')</javascript>
如何防止呢?大致思路有三種:
1. 正則表達(dá)式的白名單過濾機(jī)制。
2. 正則表達(dá)式的黑名單替換機(jī)制。
3. 通過DOM對象過濾白名單和黑名單的標(biāo)簽。
下面這個(gè)地址列舉了很多這樣的過濾方法:
http://refactormycode.com/codes/333-sanitize-html
不過,我試了上面鏈接里的一些方法,并不是很好用。有一個(gè)更簡單好用的東西,就是AntiXSS,由微軟推出的用于防止XSS攻擊的一個(gè)類庫。它的實(shí)現(xiàn)原理也是使用白名單機(jī)制,不過這個(gè)白名單對我們來說是一個(gè)黑盒,我用reflector粗略看了一下,也沒找到所謂的白名單在哪里。不過,這個(gè)庫確實(shí)很好用。
一個(gè)MSDN里圖文并茂的使用說明:http://msdn.microsoft.com/en-us/library/aa973813.aspx
其實(shí)我用的很簡單,就是AntiXss.GetSafeHtmlFragment(html)方法,這個(gè)方法會替換掉html里的危險(xiǎn)字符。比如:
var html = "<a href=\"#\" onclick=\"alert();\">aaaaaaaaa</a>javascript<P><IMG SRC=javascript:alert('XSS')><javascript>alert('a')</javascript><IMG src=\"abc.jpg\"><IMG><P>Test</P>";
string safeHtml = AntiXss.GetSafeHtmlFragment(html);
Console.WriteLine(safeHtml);
上面的危險(xiǎn)內(nèi)容被成功替換,返回的內(nèi)容是:
<a href="">aaaaaaaaa</a>javascript
<p><img src="">alert('a')<img src="abc.jpg"><img></p>
<p>Test</p>
嗯,非常安全。然后,又有一個(gè)疑問了,是應(yīng)該將用戶的輸入過濾之后寫入數(shù)據(jù)庫呢?還是在輸出界面顯示的時(shí)候進(jìn)行過濾?其實(shí),通常來講,在輸出界面顯示的時(shí)候進(jìn)行過濾就夠了,將用戶輸入過濾后寫入數(shù)據(jù)庫不是很必要,因?yàn)榧词惯@樣也無法保證數(shù)據(jù)庫中沒有危險(xiǎn)的數(shù)據(jù)。當(dāng)然,上個(gè)雙保險(xiǎn)也沒有什么不好的。