大家好,我是宝弟!
今天给大家推荐一个.Net的跨站脚本攻击(XSS)过滤器AntiXssUF,AntiXssUF以白名单的过滤策略,支持多种过滤策略。
AntiXssUF可以根据业务场景选择适合的过滤策略,或者根据用户角色动态绑定过滤策略,支持OwaspAntisamy项目的配置,支持json格式的配置。.

验证规则
protected virtual bool Validate(ICssProperty attr){if (attr == null) return false;var property = Policy.CssProperty(attr.Name);if (property == null) return false;return Policy.ValidateAttribute(property, attr.Value) || (property.Shorthands?.Any(shorthandPropertyName => Policy.ValidateAttribute(Policy.CssProperty(shorthandPropertyName), attr.Value)) ?? false);}
protected virtual bool Validate(ICssStyleDeclaration styles){if (styles == null) return false;var removings = new List<ICssProperty>();foreach (ICssProperty item in styles){if (!Validate(item)) removings.Add(item);}foreach (var item in removings){styles.RemoveProperty(item.Name);}return styles.Length > 0;}
protected virtual bool Validate(ICssRule rule){if (rule is ICssStyleRule styleRule){return Validate(styleRule.Style);}else if (rule is ICssGroupingRule groupingRule){return groupingRule.Rules.All(child => Validate(child));}else if (rule is ICssPageRule pageRule){return Validate(pageRule.Style);}else if (rule is ICssKeyframesRule keyFramesRule){return keyFramesRule.Rules.OfType<ICssKeyframeRule>().All(child => Validate(child));}else if (rule is ICssKeyframeRule keyFrameRule){return Validate(keyFrameRule.Style);}else if (rule is ICssImportRule importRule){return EmbedStyleSheets;}return false;}
过滤规则
protected virtual string Filters(ICssStyleSheet cssStyleSheet){if (cssStyleSheet == null || cssStyleSheet.Rules.Length == 0) return string.Empty;for (var i = 0; i < cssStyleSheet.Rules.Length;){ICssRule rule = cssStyleSheet.Rules[i];if (!Validate(rule))cssStyleSheet.RemoveAt(i);elsei++;}return cssStyleSheet.ToCss();}
过滤样式
public string Filters(string code){if (string.IsNullOrWhiteSpace(code)) return string.Empty;var parser = new CssParser(new CssParserOptions{IsIncludingUnknownDeclarations = true,IsIncludingUnknownRules = true,IsToleratingInvalidSelectors = true});ICssStyleSheet styleSheet;try{styleSheet = parser.ParseStyleSheet(code);if (styleSheet == null || styleSheet.Rules.Length == 0){var d = parser.ParseDeclaration(code);if (Validate(d)) { return d.ToCss(); }else { return string.Empty; }}}catch (Exception ex){throw ex;}return Filters(styleSheet);}
在启动类Startup.cs上添加依赖注入
public void ConfigureServices(IServiceCollection services){//添加策略和设置默认策略services.AddXssFilter(opt => opt.DefaultSchemeName = "DefaultPolicy").AddScheme<AntisamyPolicy>("antisamy", () => File.ReadAllTextAsync(Path.Combine(HostEnvironment.ContentRootPath, "resources/antisamy.xml"))).AddScheme<AntisamyPolicy>("anythinggoes", () => File.ReadAllTextAsync(Path.Combine(HostEnvironment.ContentRootPath, "resources/antisamy-anythinggoes.xml"))).AddScheme<AntisamyPolicy>("ebay", () => File.ReadAllTextAsync(Path.Combine(HostEnvironment.ContentRootPath, "resources/antisamy-ebay.xml"))).AddScheme<AntisamyPolicy>("myspace", () => File.ReadAllTextAsync(Path.Combine(HostEnvironment.ContentRootPath, "resources/antisamy-myspace.xml"))).AddScheme<AntisamyPolicy>("slashdot", () => File.ReadAllTextAsync(Path.Combine(HostEnvironment.ContentRootPath, "resources/antisamy-slashdot.xml"))).AddScheme<AntisamyPolicy>("test", () => File.ReadAllTextAsync(Path.Combine(HostEnvironment.ContentRootPath, "resources/antisamy-test.xml"))).AddScheme<JsonFilterPolicy>("DefaultPolicy", () => File.ReadAllTextAsync(Path.Combine(HostEnvironment.ContentRootPath, "resources/DefaultPolicy.json")));;//添加模型绑定器services.AddControllers(options =>{options.ModelBinderProviders.Insert(0, new RichTextBinderProvider());});services.AddControllersWithViews();}
在构造函数注入依赖
//依赖注入public HomeController(IFilterPolicyFactory policyFactory){this.policyFactory = policyFactory;}public async Task<IActionResult> Test(string source){var policyName = "ebay"//策略名称var filter = await policyFactory.CreateHtmlFilter(policyName);//创建过滤器var clean = filter.Filters(source);//过滤危险代码return Content(clean);}
使用模型绑定器
//模型绑定过滤策略public class TestModel{public string Name { get; set; }[XssSchemeName("ebay")]public RichText RichText { get; set; }}
在控制器上直接使用
public IActionResult Test(TestModel model){string clean = model?.RichText;//这里自动过滤危险代码return Content(clean ?? string.Empty);}//使用参数绑定过滤策略public IActionResult Test([XssSchemeName("ebay")] RichText richText){string clean = richText;//这里自动过滤危险代码return Content(clean ?? string.Empty);}
不使用依赖注入,直接使用
1、使用内置的默认策略
//使用参数绑定过滤策略,这里需要添加模型绑定器public IActionResult Test(RichText richText){string clean = richText;//这里自动过滤危险代码return Content(clean ?? string.Empty);}//这里不需要添加模型绑定器public IActionResult Test(string source){RichText richText = source;string clean = richText;//这里自动过滤危险代码return Content(clean ?? string.Empty);}
2、指定策略
public IActionResult Test(string source){var policy = new AntisamyPolicy();//json格式用JsonFilterPolicy类policy.Init(File.ReadAllText("c:/www/resources/antisamy-ebay.xml"), "ebay");var filter = new HtmlFilter(policy);var clean = filter.Filters(source);//过滤危险代码return Content(clean ?? string.Empty);}
资源获取方式
https://gitee.com/ufangx/AntiXssUF