[Security]Cross-Site Scripting(XSS)的簡介與預防

  • 30897
  • 0
  • 2011-12-21

[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上的說明:

  1. 盜用 cookie ,獲取敏感資訊。
  2. 利用植入 Flash ,透過 crossdomain 許可權設定進一步獲取更高許可權;或者利用Java等得到類似的操作。
  3. 利用 iframe、frame、XMLHttpRequest或上述Flash等方式,以(被攻擊)使用者的身份執行一些管理動作,或執行一些一般的如發微博、加好友、發私信等操作。
  4. 利用可被攻擊的域受到其他域信任的特點,以受信任來源的身份請求一些平時不允許的操作,如進行不當的投票活動。
  5. 在存取量極大的一些頁面上的XSS可以攻擊一些小型網站,實作DDoS攻擊的效果。

 

原始範例
這邊舉的例子是最簡單最常見的例子,用來表達XSS基本原理。(實際的XSS攻擊手法多到讓人吃驚,可以參考這邊

  1. 畫面上讓user輸入Id與Name,輸入後點選Save,存入對應的Table中。
    input

    程式碼: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");
        }
  2. 在另一個頁面,從Table中讀取該筆資料出來,使用<span>,或是ASP.NET中的Label server control來呈現。
    Show

    
        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片段。
TryScript

然而,在ASP.NET預設的設定裡面,會出現這樣的錯誤:
defaultDefense

上面寫著,偵測到Request.Form裡面有值可能是惡意的程式碼。『這個值可能表示有人嘗試危害應用程式的安全性,例如跨站台的指令碼處理攻擊』。

也就是說,ASP.NET預設,透過exception幫工程師處理掉這一段可能發生的問題。但若是工程師沒去瞭解原因,只為了讓程式可以動,跟著上面的說明將web.config的httpRuntime區段的requestValidationMode屬性設成2.0,並將該網頁的validateRequest設定為false,他就發現他的程式可以動了,資料也可以正常的被存入table中。(Show.aspx可能不是他寫的)就這樣開啟了XSS的大門。

當設定打開時,這樣的情形就會發生:
scriptWork

當導到這一頁的時候,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那一頁可以正常的呈現輸入的字串。
encodeResult

原始碼會將<轉成&lt;,將>轉成&gt;。

其實,比較嚴謹的作法,除了檢查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,有幾個編碼方法可以使用。
anitXSSEncode

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:

  1. Check that ASP.NET request validation is enabled.
  2. Review ASP.NET code that generates HTML output.
  3. Determine whether HTML output includes input parameters.
  4. Review potentially dangerous HTML tags and attributes.
  5. Evaluate countermeasures.


工程師最忌諱為了解決眼前的問題,而造成更大且看不見的問題。就像挖了一個洞,不補,只能紙糊上去。後面的人一走過去,就會栽跟斗一樣。當合理的exception出現時,請去瞭解上面的相關資訊,切勿直接在網路上搜尋,或是不明事理的就把一些相關的安全性設定取消。

XSS的影響範圍很大,一旦最前面的資料輸入端沒有先處理好,讓髒資料進去DB後,要找到這些資料並清掉它,不是一件容易的事。身為一個Web程式設計師,SQL injection與XSS是兩個最基本的專業素養,請務必瞭解原理,並學會如何設計防範。

Reference

  1. Wiki
  2. AntiXSS library
  3. XSS攻擊防禦技術白皮書
  4. How To: Prevent Cross-Site Scripting in ASP.NET

blog 與課程更新內容,請前往新站位置:http://tdd.best/