[Security]Cross-Site Scripting(XSS)的簡介與預防
前言
上一篇提到了SQL injection的攻擊原理,以及如何透過parameter來避免SQL injection的發生。這一篇則要介紹在Web上可能容易被忽略的問題:Cross-Site Scripting (原縮寫應為CSS,但要與Cascading Style Sheets區隔,所以簡稱為XSS)。
這篇文章會介紹一下XSS的基本原理,以及在ASP.NET上的防禦措施。
什麼是XSS
網頁基本上就是由HTML, CSS, JavaScript所組成,透過Browser來解析與呈現。而網頁上的資料,可能hard-code,可能由DataBase讀出來,可能由使用者透過<input>輸入後再以不同的HTML tag呈現。
這意味著,如果資料來源的『資料本身』,就是由HTML, CSS或JavaScript語法組成,那麼呈現的時候,這些資料就可能變成『可執行的語法』,進而可能導致其他使用者在瀏覽網頁時,被這樣注入的惡意程式碼所影響
常見攻擊手段與目的
這邊引用wiki上的說明:
- 盜用 cookie ,獲取敏感資訊。
- 利用植入 Flash ,透過 crossdomain 許可權設定進一步獲取更高許可權;或者利用Java等得到類似的操作。
- 利用 iframe、frame、XMLHttpRequest或上述Flash等方式,以(被攻擊)使用者的身份執行一些管理動作,或執行一些一般的如發微博、加好友、發私信等操作。
- 利用可被攻擊的域受到其他域信任的特點,以受信任來源的身份請求一些平時不允許的操作,如進行不當的投票活動。
- 在存取量極大的一些頁面上的XSS可以攻擊一些小型網站,實作DDoS攻擊的效果。
原始範例
這邊舉的例子是最簡單最常見的例子,用來表達XSS基本原理。(實際的XSS攻擊手法多到讓人吃驚,可以參考這邊)
-
畫面上讓user輸入Id與Name,輸入後點選Save,存入對應的Table中。
程式碼:input.aspx.cs
protected void btnSave_Click(object sender, EventArgs e) { var person = new Person { Id = this.txtId.Text, Name = this.txtName.Text }; var memberDAO = new MemberDAO(); memberDAO.Save(person); Response.Redirect("Show.aspx"); }
-
在另一個頁面,從Table中讀取該筆資料出來,使用<span>,或是ASP.NET中的Label server control來呈現。
protected void Page_Load(object sender, EventArgs e) { var person = new MemberDAO().Read(); this.Id.Text = person.Id; this.Name.Text = person.Name; }
嘗試輸入可執行的JavaScript語法
當user在Name的<input>中輸入了<script>alert(0);</script>,企圖讓可執行的JavaScript語法,經過server處理後存到DataBase,讓Show呈現的時候,執行這一段可執行的JavaScript片段。
然而,在ASP.NET預設的設定裡面,會出現這樣的錯誤:
上面寫著,偵測到Request.Form裡面有值可能是惡意的程式碼。『這個值可能表示有人嘗試危害應用程式的安全性,例如跨站台的指令碼處理攻擊』。
也就是說,ASP.NET預設,透過exception幫工程師處理掉這一段可能發生的問題。但若是工程師沒去瞭解原因,只為了讓程式可以動,跟著上面的說明將web.config的httpRuntime區段的requestValidationMode屬性設成2.0,並將該網頁的validateRequest設定為false,他就發現他的程式可以動了,資料也可以正常的被存入table中。(Show.aspx可能不是他寫的)就這樣開啟了XSS的大門。
當設定打開時,這樣的情形就會發生:
當導到這一頁的時候,Person.Name的資料是『<script>alert(0);</script>』,所以頁面就直接執行了這一段script。
怎麼會這樣?檢查一下網頁的原始碼,可以發現那一段script已經被『注入』到Name的<span中>。
什麼時候需要將ValidateRequest設定為false
當畫面上的輸入項需要以文字方式,而非HTML語法存入時,就只能將web.config與validateRequest設定好,讓user可以輸入相關的資料。但,這樣的資料需要經過『編碼』,讓可能為HTML語法的資料,轉成純文字來呈現。最常見的例子,可能是要輸入XML或是HTML資料。(其實論壇或是正在寫Blog文章的現在,也是會將"<" ">" 這類的字元,經過HtmlEncode,轉成文字)
如何避免XSS
簡單的說,過濾可能為惡意的程式碼。(如同SQL injection一樣)
SQL injection可以透過parameter,XSS呢?最基本的處理,可以透過HtmlEncode來處理。
修改Input.aspx.cs程式碼
protected void btnSave_Click(object sender, EventArgs e)
{
////將id與name,經過HtmlEncode,將可能的html語法都轉成文字形式
var id = HttpUtility.HtmlEncode(this.txtId.Text);
var name = HttpUtility.HtmlEncode(this.txtName.Text);
var person = new Person { Id = id, Name = name };
var memberDAO = new MemberDAO();
memberDAO.Save(person);
Response.Redirect("Show.aspx");
}
結果就會變成,輸入的<script>在Show那一頁可以正常的呈現輸入的字串。
原始碼會將<轉成<,將>轉成>。
其實,比較嚴謹的作法,除了檢查input項目,QueryString, Post過來的資料等等,也都應該經過這樣的編碼或檢查,方能確保從網頁進去的資料,不會存在惡意的程式碼。
另一種是要Render到畫面的,都經過HtmlEncode,這樣也行,但代表資料可能已經是『可執行的惡意程式碼』,導致的隱憂會多很多。
所以通常是採第一種從資料輸入來源進行過濾,或是1+2,除了輸入來源,連呈現的部分也要編碼。
更大的問題
什麼時候會碰到更大的問題?就是在CMS(Context Management System)系統上,也就是可以讓user編輯頁面資料與排版的系統。這類系統幾乎避免不掉讓user輸入HTML,甚至JavaScript與CSS。這類需求就無法單純使用編碼來解決,通常的方式還是透過白名單來過濾。
慶幸的是,許多HtmlEditor都有注意到這一點,可以透過屬性設定,來過濾掉大部分可能的惡意程式碼。對應的缺點是,可能連沒有惡意企圖的正常資料,因為用了有安全疑慮的tag,而導致被清掉。(這是沒辦法的事,除非把安全把關的功能關掉,自行設計過濾字元的功能)
在ASP.NET中,Microsoft Web Protection Library提供了一個Library,專門用來處理XSS的事務,請參考:AntiXSS Library V4.0
在4.0以前的版本,只有使用一顆AntiXSSLibrary.dll,4.0版本,則把常用的編碼方法抽到了另一顆dll:HtmlSanitizationLibrary.dll,在Sanitizer Class,有幾個編碼方法可以使用。
AntiXSS library提供了許多自訂過濾清單的功能,這邊礙於篇幅限制,就不多說了,請安裝完AntiXSSLibrary後,參考AntiXSS.chm。(預設路徑在C:\Program Files (x86)\Microsoft Information Security\AntiXSS Library v4.0)
[註]要注意需在.net framework 3.5以上,方能使用AntiXSS 4.0的版本。如果是比較低的.net framework 版本,請找更之前的AntiXSS library的版本。(載點:AntiXSS Library 3.1,支援.net framework 2.0)
結論
在patterns & practices Developer Center簡單歸納出五個步驟防止XSS:
- Check that ASP.NET request validation is enabled.
- Review ASP.NET code that generates HTML output.
- Determine whether HTML output includes input parameters.
- Review potentially dangerous HTML tags and attributes.
- Evaluate countermeasures.
工程師最忌諱為了解決眼前的問題,而造成更大且看不見的問題。就像挖了一個洞,不補,只能紙糊上去。後面的人一走過去,就會栽跟斗一樣。當合理的exception出現時,請去瞭解上面的相關資訊,切勿直接在網路上搜尋,或是不明事理的就把一些相關的安全性設定取消。
XSS的影響範圍很大,一旦最前面的資料輸入端沒有先處理好,讓髒資料進去DB後,要找到這些資料並清掉它,不是一件容易的事。身為一個Web程式設計師,SQL injection與XSS是兩個最基本的專業素養,請務必瞭解原理,並學會如何設計防範。
Reference
blog 與課程更新內容,請前往新站位置:http://tdd.best/