一个.Net的跨站脚本攻击(XSS)过滤器,以白名单的过滤策略,支持多种过滤策略

大家好,我是宝弟!

今天给大家推荐一个.Net的跨站脚本攻击(XSS)过滤器AntiXssUF,AntiXssUF以白名单的过滤策略,支持多种过滤策略。

AntiXssUF可以根据业务场景选择适合的过滤策略,或者根据用户角色动态绑定过滤策略,支持OwaspAntisamy项目的配置,支持json格式的配置。.

项目结构

一个.Net的跨站脚本攻击(XSS)过滤器,以白名单的过滤策略,支持多种过滤策略

主要方法
 

验证规则

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);        else            i++;    }    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