• 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
        {
    
        }
    View Code

    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;
                    }
                }
            }
        }
    View Code

    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;
            }
        }
    }
    View Code

    Step4:在Web站点启动的时候,配置MVC框架 

    RouteTableRegister.RegisterRoutes(_routes);
    
                BundleConfig.RegisterBundles(BundleTable.Bundles);
    
                ModelMetadataProviders.Current = new CustomModelMetadataProvider();
                ModelBinders.Binders.DefaultBinder = new AntiXssModelBinder();
    View Code

    举例: 

    [Required]
         [AllowHtml]
         public string UserName{get;set;}
         [Required]
         public string Password{get;set;}
         注意:这时通过JSON传过来的数据Password就会报错,而UserName则不会。
    View Code

    如果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;
            }
        }
         
    View Code

    如果某些参数需要支持部分HTML代码,可以采取先将该参数设置为[AllowHTML],值传到Action时,再进行手动过滤,或者 使用AntiXSS库进行编码(微软提供的AntiXSSLibrary类库)。 

    非常感谢您的耐心观看,您的关注是我最大的动力! 不积跬步无以至千里,不积小流无以成江海!
  • 相关阅读:
    [Python]ConfigParser解析配置文件
    Jenkins(二)
    [置顶] NB多项式事件模型、神经网络、SVM之函数/几何间隔——斯坦福ML公开课笔记6
    “冗余”的参数(变量) —— 提升访问的效率
    Python Tricks(二十)—— 阶乘的极简实现
    Python Tricks(二十)—— 阶乘的极简实现
    常见问题与常见算法的时间复杂度
    常见问题与常见算法的时间复杂度
    算法中的优化问题(optimization problem)
    算法中的优化问题(optimization problem)
  • 原文地址:https://www.cnblogs.com/sheldon-blog/p/8108176.html
Copyright © 2020-2023  润新知