ASP.NET MVC3 更安全的限定可以輸入 HTML 的欄位
- 2011-08-21
- 31916
- 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 提醒)








Roslyn 魔法工坊:打造你的 Source Generator [2025-12-20]開課 共7H
回應討論