.netcore 处理xss攻击,做输入验证

冯宪
2023-12-01

开发中我们往往需要给用户输入做一些特殊的过滤,主要的是防止xss攻击,至于一般的,有MaxLengthAttribute PhoneAttribute RegularExpressionAttribute等。

MaxLengthAttribute 类 (System.ComponentModel.DataAnnotations) | Microsoft Docs

上面是校验是否通过,我们这次做一个替换的,主要目的是防止xss工具,原理是比如在用户的输入字段中包裹一些js或者引入外部js等然后浏览器访问了,就可以执行这个脚本。

定义一个过滤器给模型用,主要是标注下哪些模型是使用富文本过滤的,毕竟我的思路是普通的字符串直接替换<>符号,至于富文本则有其他的规则。

    public class EditHtmlAttribute : Attribute
    {
        public EditHtmlAttribute() { }
    }

定义一个过滤器:

    /// <summary>
    /// XSS工具过滤
    /// </summary>
    public class XSSAttribute : ActionFilterAttribute
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            //post的xss过滤如何行驶?
            //获取Action参数集合
            var ps = context.ActionDescriptor.Parameters;
            //遍历参数集合
            foreach (var p in ps)
            {
                if (context.ActionArguments[p.Name] != null)
                {
                    //当参数等于字符串
                    if (p.ParameterType.Equals(typeof(string)))
                    {                       
                        context.ActionArguments[p.Name] = StringFilter(context.ActionArguments[p.Name].ToString());
                    }
                    else if (p.ParameterType.IsClass)//当参数等于类
                    {
                        ModelFieldFilter(p.Name, p.ParameterType, context.ActionArguments[p.Name]);
                    }
                }

            }
            base.OnActionExecuting(context);
        }

        /// <summary>
        /// 遍历修改类的字符串属性
        /// </summary>
        /// <param name="key">类名</param>
        /// <param name="t">数据类型</param>
        /// <param name="obj">对象</param>
        /// <returns></returns>
        private object ModelFieldFilter(string key, Type t, object obj)
        {
            //获取类的属性集合
            var ats = t.GetCustomAttributes(typeof(XSSAttribute), false);
            if (obj != null)
            {
                //获取类的属性集合
                var pps = t.GetProperties();

                foreach (var pp in pps)
                {
                    if (pp.GetValue(obj) != null)
                    {
                        //当属性等于字符串
                        if (pp.PropertyType.Equals(typeof(string)))
                        {
                            //pp.CustomAttributes.Contains();
                            var find = false;
                            if (pp.CustomAttributes.Count() > 0)
                            {
                                foreach (var ca in pp.CustomAttributes)
                                {
                                    //是否标注了富文本
                                    if (ca.AttributeType.Name == nameof(EditHtmlAttribute))
                                    {
                                        find = true;
                                        break;
                                    }
                                    //可以扩展是否忽略校验
                                }
                            }

                            if (!find)
                            {
                                string value = pp.GetValue(obj).ToString();
                                pp.SetValue(obj, StringFilter(value));
                            }
                            else
                            {
                                    string value = pp.GetValue(obj).ToString();
                                    pp.SetValue(obj, HtmlFilter(value));                        
                            }

                        }
                        else if (pp.PropertyType.IsClass)//当属性等于类进行递归
                        {
                            pp.SetValue(obj, ModelFieldFilter(pp.Name, pp.PropertyType, pp.GetValue(obj)));
                        }
                    }

                }
            }

            return obj;
        }
        /// <summary>
        /// 基本字符串的过滤器
        /// </summary>
        /// <param name="val"></param>
        /// <returns></returns>
        private string StringFilter(string val)
        {
            if (!String.IsNullOrEmpty(val))
            {
                //这里填写普通字符串的过滤规则
                return val.Replace("<", "&lt;").Replace(">","&gt;");
            }
            return val;
        }

        /// <summary>
        /// 富文本的过滤器
        /// </summary>
        /// <param name="val"></param>
        /// <returns></returns>
        private string HtmlFilter(string val)
        {
            if (!String.IsNullOrEmpty(val))
            {
                //这里填写关于富文本的自定义过滤规则
                return val.Replace("<script", "&lt;");
            }
            return val;
        }
    }

接下来就是测试一下了。

        /// <summary>
        /// 验证html关键替换
        /// </summary>
        /// <param name="name"></param>
        /// <param name="url"></param>
        /// <returns></returns>
        [HttpPost]
        [XSSAttribute]//标注使用xss替换校验
        public string PostUrl(ModelItem input)
        {
            return Newtonsoft.Json.JsonConvert.SerializeObject(input);
        }

ModelItem的模型如下:

    public class ModelItem
    {
        /// <summary>
        /// 其他参数
        /// </summary>
        public int Age { get; set; }

        /// <summary>
        /// 一般字符串内容
        /// </summary>
        public string Str { get; set; }

        /// <summary>
        /// 富文本内容
        /// </summary>
        [EditHtmlAttribute]
        public string Html { get; set; }

    }

然后运行项目测试下!

 类似资料: