Magicodes.WeiChat——使用AntiXssAttribute阻止XSS(跨站脚本攻击)攻击

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

跨站脚本攻击(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;
        }
    }
目录
相关文章
|
5天前
|
安全 前端开发 Java
Web安全进阶:XSS与CSRF攻击防御策略深度解析
【10月更文挑战第26天】Web安全是现代软件开发的重要领域,本文深入探讨了XSS和CSRF两种常见攻击的原理及防御策略。针对XSS,介绍了输入验证与转义、使用CSP、WAF、HTTP-only Cookie和代码审查等方法。对于CSRF,提出了启用CSRF保护、设置CSRF Token、使用HTTPS、二次验证和用户教育等措施。通过这些策略,开发者可以构建更安全的Web应用。
30 4
|
4天前
|
安全 Go PHP
Web安全进阶:XSS与CSRF攻击防御策略深度解析
【10月更文挑战第27天】本文深入解析了Web安全中的XSS和CSRF攻击防御策略。针对XSS,介绍了输入验证与净化、内容安全策略(CSP)和HTTP头部安全配置;针对CSRF,提出了使用CSRF令牌、验证HTTP请求头、限制同源策略和双重提交Cookie等方法,帮助开发者有效保护网站和用户数据安全。
23 2
|
6天前
|
存储 安全 Go
Web安全基础:防范XSS与CSRF攻击的方法
【10月更文挑战第25天】Web安全是互联网应用开发中的重要环节。本文通过具体案例分析了跨站脚本攻击(XSS)和跨站请求伪造(CSRF)的原理及防范方法,包括服务器端数据过滤、使用Content Security Policy (CSP)、添加CSRF令牌等措施,帮助开发者构建更安全的Web应用。
34 3
|
1月前
|
存储 JavaScript 安全
|
1月前
|
存储 JavaScript 前端开发
Xss跨站脚本攻击(Cross Site Script)
Xss跨站脚本攻击(Cross Site Script)
|
4月前
|
存储 安全 JavaScript
手摸手带你进行XSS攻击与防御
当谈到网络安全和信息安全时,跨站脚本攻击(XSS)是一个不可忽视的威胁。现在大家使用邮箱进行用户认证比较多,如果黑客利用XSS攻陷了用户的邮箱,拿到了cookie那么就可以冒充你进行收发邮件,那真就太可怕了,通过邮箱验证进行其他各种网站的登录与高危操作。 那么今天,本文将带大家深入了解XSS攻击与对应的防御措施。
|
2月前
|
存储 安全 JavaScript
XSS跨站脚本攻击详解(包括攻击方式和防御方式)
这篇文章详细解释了XSS跨站脚本攻击的概念、原理、特点、类型,并提供了攻击方式和防御方法。
172 1
|
4月前
|
SQL 安全 数据库
Python Web开发者必学:SQL注入、XSS、CSRF攻击与防御实战演练!
【7月更文挑战第26天】在 Python Web 开发中, 安全性至关重要。本文聚焦 SQL 注入、XSS 和 CSRF 这三大安全威胁,提供实战防御策略。SQL 注入可通过参数化查询和 ORM 框架来防范;XSS 则需 HTML 转义用户输入与实施 CSP;CSRF 防御依赖 CSRF 令牌和双重提交 Cookie。掌握这些技巧,能有效加固 Web 应用的安全防线。安全是持续的过程,需贯穿开发始终。
86 1
Python Web开发者必学:SQL注入、XSS、CSRF攻击与防御实战演练!
|
3月前
|
监控 安全 JavaScript
对跨站脚本攻击(XSS)的防御策略?
【8月更文挑战第15天】
235 1
|
3月前
|
存储 安全 JavaScript
XSS攻击(Cross-Site Scripting)
【8月更文挑战第11天】
67 2