ASP.NET MVC Anti-XSS方案


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類庫)。
 
整理網絡文章,如有錯誤,敬請指正,非常感謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM