1:Form提交模式
在使用Form提交時,MVC框架提供了一個默認的機制。如果數據中含有惡意字,則會自動轉向出錯頁面。

2:Ajax+JSON提交模式。
MVC框架未提供對於Json數據的AntiXSS支持,所以必須自行實現。
Step1:定義一個Attribute[AllowHtml],如果有這個標記,則說明該屬性允許Html,不需要驗證。
/// <summary>
/// 用於標記某個屬性是否允許html字符
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class AllowHtmlAttribute : Attribute
{
}
Step2:元數據解析的時候,動態設定標記為AllowHtml的屬性不激發驗證。
public class CustomModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
public CustomModelMetadataProvider()
{
}
protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType,
Func<object> modelAccessor, Type modelType, string propertyName)
{
var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
if (containerType == null || propertyName == null)
return metadata;
foreach (Attribute attr in attributes)
{
if (attr is AllowHtmlAttribute)
{
metadata.RequestValidationEnabled = false;
break;
}
}
}
}
Step3:實現自定義ModerBinder,攔截所有的json數據,進行anti-xss驗證。
/// <summary>
/// 檢測Json數據中含有惡意字符,拋出HttpRequestValidationException
/// </summary>
public class AntiXssModelBinder : DefaultModelBinder
{
protected override bool OnPropertyValidating(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor, object value)
{
if (controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
{
int index;
if (controllerContext.Controller.ValidateRequest
&& bindingContext.PropertyMetadata[propertyDescriptor.Name].RequestValidationEnabled)
{
if (value is string)
{
if (AntiXssStringHelper.IsDangerousString(value.ToString(), out index))
{
throw new HttpRequestValidationException("Dangerous Input Detected");
}
}
else if (value is IEnumerable)
{
// 字符串數組或者集合,或者Dictionary<string, string>
// Dictionary的Key, Value會ToString后一起驗證
foreach (object obj in value as IEnumerable)
{
if (obj != null)
{
if (AntiXssStringHelper.IsDangerousString(obj.ToString(), out index))
{
throw new HttpRequestValidationException("Dangerous Input Detected");
}
}
}
}
}
}
return base.OnPropertyValidating(controllerContext, bindingContext, propertyDescriptor, value);
}
}
/// <summary>
/// 檢測綁定的單值字符串是否包含惡意字符
/// </summary>
public class AntiXssRawModelBinder : StringTrimModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var value = base.BindModel(controllerContext, bindingContext);
if (value is string)
{
var result = (value as string).Trim();
int index;
if (AntiXssStringHelper.IsDangerousString(value.ToString(), out index))
{
throw new HttpRequestValidationException("Dangerous Input Detected");
}
}
return value;
}
}
}
Step4:在Web站點啟動的時候,配置MVC框架
RouteTableRegister.RegisterRoutes(_routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
ModelMetadataProviders.Current = new CustomModelMetadataProvider();
ModelBinders.Binders.DefaultBinder = new AntiXssModelBinder();
舉例:
[Required]
[AllowHtml]
public string UserName{get;set;}
[Required]
public string Password{get;set;}
注意:這時通過JSON傳過來的數據Password就會報錯,而UserName則不會。
如果Ajax傳入的JSON是封裝好的對象,最好也要經過封裝,以下為例:
public ActionResult Login(LoginModel model,[ModelBinder(typeof(AntiXssRawModelBinder))])
{
}
//AntiXssRawModelBinder核心代碼
/// <summary>
/// 檢測綁定的單值字符串是否包含惡意字符
/// </summary>
public class AntiXssRawModelBinder : StringTrimModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var value = base.BindModel(controllerContext, bindingContext);
if (value is string)
{
var result = (value as string).Trim();
int index;
if (AntiXssStringHelper.IsDangerousString(value.ToString(), out index))
{
throw new HttpRequestValidationException("Dangerous Input Detected");
}
}
return value;
}
}
如果某些參數需要支持部分HTML代碼,可以采取先將該參數設置為[AllowHTML],值傳到Action時,再進行手動過濾,或者 使用AntiXSS庫進行編碼(微軟提供的AntiXSSLibrary類庫)。
整理網絡文章,如有錯誤,敬請指正,非常感謝!