zoukankan      html  css  js  c++  java
  • Magicodes.WeiChat——使用AntiXssAttribute阻止XSS(跨站脚本攻击)攻击

    跨站脚本攻击(Cross Site Scripting),为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS。恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的特殊目的。

    很多时候,我们并不需要屏蔽所有的HTML标签,或者,我们需要设置某些属性支持的HTML标签字符串。还好,框架中封装了相关的特性,以便你直接拿来使用。

    命名空间:Magicodes.WeiChat.Infrastructure.MvcExtension.Filters

    类名:AntiXssAttribute

    Demo:

    [AntiXss]
                  public string Name { get; set; }
    
                  [AntiXss(allowedStrings: "<br />,<p>")]
                  public string Description { get; set; }
    
                  [AntiXss(allowedStrings: "<br />", disallowedStrings:"/, #")]
                  public string NoSlashesOrHashes { get; set; }
    
                  [AntiXss(errorMessage: "This is a custom error message")]
                  public string CustomError { get; set; }
    
                  [AntiXss(errorMessageResourceName:"TestMessage", errorMessageResourceType: typeof(TestResources))]
                  public string ResourceCustomError { get; set; }

    具体代码如下所示:

    /// <summary>
        /// AntiXss验证特性,防止XSS攻击
        /// </summary>
        [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
        public class AntiXssAttribute : ValidationAttribute
        {
            const string DefaultValidationMessageFormat = "字段 {0} XSS验证失败,请检查输入的字符串中是否含有非法字符。";
            private readonly string errorMessage;
            private readonly string errorMessageResourceName;
            private readonly Type errorMessageResourceType;
            private readonly string allowedStrings;
            private readonly string disallowedStrings;
            private readonly Dictionary<string, string> allowedStringsDictionary;
    
            /// <summary>
            /// 初始化 <see cref="AntiXssAttribute"/> 的新实例.
            /// </summary>
            /// <param name="errorMessage">错误消息</param>
            /// <param name="errorMessageResourceName">获取或设置错误消息资源的名称,在验证失败的情况下,要使用该名称来查找 ErrorMessageResourceType 属性值</param>
            /// <param name="errorMessageResourceType">获取或设置在验证失败的情况下用于查找错误消息的资源类型。</param>
            /// <param name="allowedStrings">以逗号分隔的允许的字符串。</param>
            /// <param name="disallowedStrings">以逗号分隔的字符串不允许的字符或单词</param>
            public AntiXssAttribute(
                string errorMessage = null,
                string errorMessageResourceName = null,
                Type errorMessageResourceType = null,
                string allowedStrings = null,
                string disallowedStrings = null)
            {
                this.errorMessage = errorMessage;
                this.errorMessageResourceName = errorMessageResourceName;
                this.errorMessageResourceType = errorMessageResourceType;
                this.allowedStrings = allowedStrings;
                this.disallowedStrings = disallowedStrings;
                allowedStringsDictionary = new Dictionary<string, string>();
            }
            /// <summary>
            /// 确定对象的指定值是否有效。
            /// </summary>
            /// <param name="value"></param>
            /// <returns></returns>
            public override bool IsValid(object value)
            {
                return true;
            }
            /// <summary>
            /// 确定对象的指定值是否有效。
            /// </summary>
            /// <param name="value"></param>
            /// <param name="validationContext"></param>
            /// <returns></returns>
            protected override ValidationResult IsValid(object value, ValidationContext validationContext)
            {
                if (value == null)
                {
                    return base.IsValid(null, validationContext);
                }
    
                var encodedValue = EncoderHelper.HtmlEncode(value.ToString(), false);
    
                if (EncodedStringAndValueAreDifferent(value, encodedValue))
                {
                    SetupAllowedStringsDictionary();
    
                    foreach (var allowedString in allowedStringsDictionary)
                    {
                        encodedValue = encodedValue.Replace(allowedString.Value, allowedString.Key);
                    }
    
                    if (EncodedStringAndValueAreDifferent(value, encodedValue))
                    {
                        return new ValidationResult(SetErrorMessage(validationContext));
                    }
                }
    
                if (!string.IsNullOrWhiteSpace(disallowedStrings)
                    && disallowedStrings.Split(',').Select(x => x.Trim()).Any(x => value.ToString().Contains(x)))
                {
                    return new ValidationResult(SetErrorMessage(validationContext));
                }
    
                return base.IsValid(value, validationContext);
            }
    
            private static bool EncodedStringAndValueAreDifferent(object value, string encodedValue)
            {
                return !value.ToString().Equals(encodedValue);
            }
    
            private void SetupAllowedStringsDictionary()
            {
                if (string.IsNullOrWhiteSpace(allowedStrings))
                {
                    return;
                }
    
                foreach (var allowedString in allowedStrings.Split(',').Select(x => x.Trim())
                    .Where(allowedString => !allowedStringsDictionary.ContainsKey(allowedString)))
                {
                    allowedStringsDictionary.Add(allowedString,
                        EncoderHelper.HtmlEncode(allowedString, false));
                }
            }
            /// <summary>
            /// 设置错误消息
            /// </summary>
            /// <param name="validationContext"></param>
            /// <returns></returns>
            private string SetErrorMessage(ValidationContext validationContext)
            {
                if (IsResourceErrorMessage())
                {
                    var resourceManager = new ResourceManager(errorMessageResourceType);
                    return resourceManager.GetString(errorMessageResourceName, CultureInfo.CurrentCulture);
                }
    
                if (!string.IsNullOrEmpty(errorMessage))
                {
                    return errorMessage;
                }
    
                return string.Format(DefaultValidationMessageFormat, validationContext.DisplayName);
            }
    
            private bool IsResourceErrorMessage()
            {
                return !string.IsNullOrEmpty(errorMessageResourceName) && errorMessageResourceType != null;
            }
        }
  • 相关阅读:
    豆瓣书籍数据采集
    动画精灵与碰撞检测
    图形
    模块
    对象
    函数
    列表与字典
    python 感悟
    SqlServer自动备份数据库(没有sql代理服务的情况下)
    关于AD获取成员隶属于哪些组InvokeGet("memberOf")的问题
  • 原文地址:https://www.cnblogs.com/codelove/p/5484106.html
Copyright © 2011-2022 走看看