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;
        }
    }
目录
相关文章
|
1月前
|
JavaScript 安全 前端开发
js开发:请解释什么是XSS攻击和CSRF攻击,并说明如何防范这些攻击。
XSS和CSRF是两种常见的Web安全威胁。XSS攻击通过注入恶意脚本盗取用户信息或控制账户,防范措施包括输入验证、内容编码、HTTPOnly Cookie和CSP。CSRF攻击则诱使用户执行未经授权操作,防范手段有CSRF Tokens、双重验证、Referer检查和SameSite Cookie属性。开发者应采取这些防御措施并定期进行安全审计以增强应用安全性。
21 0
|
1天前
|
缓存 安全 JavaScript
前端安全:Vue应用中防范XSS和CSRF攻击
【4月更文挑战第23天】本文探讨了在Vue应用中防范XSS和CSRF攻击的重要性。XSS攻击通过注入恶意脚本威胁用户数据,而CSRF则利用用户身份发起非授权请求。防范措施包括:对输入内容转义、使用CSP、选择安全的库;采用Anti-CSRF令牌、同源策略和POST请求对抗CSRF;并实施代码审查、更新依赖及教育团队成员。通过这些实践,可提升Vue应用的安全性,抵御潜在攻击。
|
9天前
|
安全 JavaScript Go
跨站脚本攻击(XSS)防护在Django中的应用
【4月更文挑战第15天】本文介绍了Django如何防范XSS攻击。Django模板引擎自动转义HTML以防止恶意脚本,提供`mark_safe`函数和CSRF防护。此外,建议开发者验证清理用户输入、使用内容安全策略、更新库以及遵循安全编码实践来增强防护。通过这些措施,开发者能构建更安全的Web应用。
|
1月前
|
安全 JavaScript 前端开发
Low 级别反射型 XSS 演示(附链接)
Low 级别反射型 XSS 演示(附链接)
19 0
|
1月前
|
存储 JavaScript 前端开发
DOM 型 XSS 演示(附链接)
DOM 型 XSS 演示(附链接)
70 0
|
1月前
|
存储 前端开发 JavaScript
存储型 XSS 攻击演示(附链接)
存储型 XSS 攻击演示(附链接)
81 0
|
1月前
|
存储 前端开发 JavaScript
反射型 XSS 攻击演示(附链接)
反射型 XSS 攻击演示(附链接)
134 0
|
2月前
|
存储 安全
第二轮学习笔记:XSS跨站脚本漏洞
第二轮学习笔记:XSS跨站脚本漏洞
24 0
|
3月前
|
存储 JSON 前端开发
【面试题】XSS攻击是什么?
【面试题】XSS攻击是什么?
|
3月前
|
存储 开发框架 安全
如何处理预防XSS漏洞攻击问题
防止XSS攻击需要从多个方面入手,包括输入验证和过滤、输出编码、设置正确的HTTP头部、使用最新的安全框架和库、定期进行安全审计和漏洞扫描以及培训和意识提升等。只有综合运用这些措施,才能有效地防止XSS攻击,保护网站和用户的安全。