demoshop

demo, trying to be the best_

製作網站時常有要讓表單能輸入HTML的需求,但為了安全性,ASP.NET預設都會阻擋這類行為來避免攻擊。不過實務上確實有需要讓一些表單允許輸入語法,在 Web form 和 MVC 也都有提供相關的設定,不過在 ASP.NET MVC3 上增加了一個更安全的設定方式,讓網站的整體安全性更加分。

demo廢言為求方便示範 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>
}

demo廢言好!前置結束,現在來看主題,頁面中包含了兩個 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 的語法了


demo廢言網頁的安全是每個一個網站開發人員時時刻刻要注意的事情,千萬不要因為偷懶而造成重大的傷害。

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 提醒)

 

 

 

 

回應討論