zoukankan      html  css  js  c++  java
  • 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类库)。
     
    整理网络文章,如有错误,敬请指正,非常感谢!
  • 相关阅读:
    少儿编程之我见
    异常处理:java.lang.ClassNotFoundException: javax.xml.bind.JAXBContext
    Maven异常:Could not find artifact
    三种使用分布式锁方案
    技术栈
    给定一个数组,求两数之和等于某个值
    链表--部分知识点整理
    链表
    php序列化和反序列化学习
    data类型的url
  • 原文地址:https://www.cnblogs.com/jayden-en/p/6239153.html
Copyright © 2011-2022 走看看