ASP.NET MVC3 更安全的限定可以輸入 HTML 的欄位
- 2011-08-21
- 29959
- 0
- ASP.NET MVC3 驗證介紹實作與擴充
製作網站時常有要讓表單能輸入HTML的需求,但為了安全性,ASP.NET預設都會阻擋這類行為來避免攻擊。不過實務上確實有需要讓一些表單允許輸入語法,在 Web form 和 MVC 也都有提供相關的設定,不過在 ASP.NET MVC3 上增加了一個更安全的設定方式,讓網站的整體安全性更加分。
為求方便示範 demo 在 HomeController 內增加一個 Class 要拿來做 Model ,這個 Class 只有兩個 屬性 分別就是純文字和HTML ,因為這些前置動作不是重點,所以就直接貼 Code 帶過。
完整的HomeController.cs
using System; using System.Collections.Generic; using System.Linq; using System.Web.Mvc; using System.ComponentModel.DataAnnotations; namespace MvcApplication1.Controllers { public class HomeController : Controller { public ActionResult Index(FormCollection c) { ViewBag.Message = "Welcome to ASP.NET MVC!"; ViewData["PureText"] = c["PureText"]; ViewData["HTML"] = c["HTML"]; return View(); } public ActionResult About() { return View(); } } public class testModels { [Display(Name = "純文字")] public string PureText { get; set; } [Display(Name = "富本文")] public string HTML { get; set; } } }
完整的 Home\Index
@model MvcApplication1.Controllers.testModels @{ ViewBag.Title = "Home Page"; } <h2>@ViewBag.Message</h2> <p> To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>. </p> @using (Html.BeginForm()) { <div> <p>PureText:@ViewData["PureText"]</p> <p>HTML:@ViewData["HTML"]</p> <fieldset> <legend>Test</legend> <div class="editor-label"> @Html.LabelFor(m => m.PureText) </div> <div class="editor-field"> @Html.TextAreaFor(m => m.PureText) @Html.ValidationMessageFor(m => m.PureText) </div> <div class="editor-label"> @Html.LabelFor(m => m.HTML) </div> <div class="editor-field"> @Html.TextAreaFor(m => m.HTML) @Html.ValidationMessageFor(m => m.HTML) </div> <p> <input type="submit" value="Register" /> </p> </fieldset> </div> }
好!前置結束,現在來看主題,頁面中包含了兩個 TextArea ,設計的需求是一個只能輸入「純文字」另一個可以輸入「語法」,現在我們分別這樣輸入
按下「Register」後立即可以看到錯誤
具有潛在危險 Request.Form 的值已從用戶端 (HTML="我很<b>富</b>") 偵測到。
為了解決此驗證,之前就是依據【ASP.NET MVC validateRequest 取消驗證失效?】 一文中所介紹的 ValidateInput Attribute,來設定某個 Action 不要驗證。
[ValidateInput(false)] public ActionResult Index(FormCollection c) { ViewBag.Message = "Welcome to ASP.NET MVC!"; ViewData["PureText"] = c["PureText"]; ViewData["HTML"] = c["HTML"]; return View(); }
記得要 Build
雖然使用了上述方法可以成功的避開驗證,但這其實造成了另一個安全性的隱憂,在開發的時候我們很直覺的知道 HTML 欄位可以接受語法,而 PureText 欄位不能接受語法,所以增加的安全性判斷或檢查等功都會做在 HTML 這個欄位上,但其實你開放的是整個表單都可以接受語法
看上圖可以看得出來兩個欄位都輸入了語法,這並非我們所期望的。
會顯示出語法而不是產生效果是因為 ASP.NET MVC3 預設的文字輸出都是 HTMLEncode ,這也是一個提高安全性的預設值。
為了避免這種一開就要全開的不安全寫法,在 ASP.NET MVC3 增加了 AllowHTML 的屬性(Attribute),設定的方式也從 Action 改成由 Class 屬性(property)設定。
public class testModels { [Display(Name = "純文字")] public string PureText { get; set; } [AllowHtml] [Display(Name = "富本文")] public string HTML { get; set; } }
記得要 Build 而且也要把原本在 Action 的 ValidateInput 設定拿掉
同樣的輸入值再次輸入就可以看到確實的擋住了 PureText 的語法了
網頁的安全是每個一個網站開發人員時時刻刻要注意的事情,千萬不要因為偷懶而造成重大的傷害。
AllowHtml 的 Code 如下
[AttributeUsage(AttributeTargets.Property, AllowMultiple=false, Inherited=true)] public sealed class AllowHtmlAttribute : Attribute, IMetadataAware { // Methods public void OnMetadataCreated(ModelMetadata metadata) { if (metadata == null) { throw new ArgumentNullException("metadata"); } metadata.RequestValidationEnabled = false; } }
如果您使用了以上的作法卻還是無法正常的開放語法請在 Global.asax 中的 Application_Start 中加上下方 Code
ModelMetadataProviders.Current = new DataAnnotationsModelMetadataProvider();
請注意!即使只有允許單一表單欄位開放語法,還是無法防範 XSS 等相似的攻擊,請務必還是要自行過濾危險語法或是可以使用微軟推出的 AntiXSS 類別庫來過濾此類攻擊。(感謝網友 KKBruce 提醒)
回應討論