通过内容安全策略(CSP)增强Web应用安全性

在当今的网络世界中,Web应用的安全性至关重要。其中,跨站脚本攻击(XSS)是一种常见的攻击方式,它允许攻击者在用户的浏览器上执行恶意脚本。为了防范此类攻击,内容安全策略(Content Security Policy,简称CSP)提供了一种额外的安全层。CSP可以帮助开发者指定可信的源(域名),以限制可执行脚本的来源。通过使用CSP,可以有效地防止恶意脚本在用户浏览器上的执行。

CSP的基本概念

CSP通过设置HTTP头中的Content-Security-Policy字段来实现。这个字段由一系列的指令和源组成,用分号分隔。指令定义了资源类型的限制,而源则指定了可信的域名。例如,可以设置script-src指令来限制JavaScript脚本的来源,只允许来自特定域名的脚本执行。

CSP的指令和源

CSP的指令用于指定资源类型的限制,常见的指令包括:

  • script-src:定义JavaScript脚本的有效来源
  • style-src:定义样式表的有效来源
  • img-src:定义图片的有效来源
  • connect-src:定义AJAX调用的有效目标
  • font-src:定义字体的有效来源
  • object-src:定义<object>、<embed>和<applet>元素的有效来源
  • media-src:定义音频和视频的有效来源
  • form-action:定义表单提交的有效目标
  • default-src:指定加载内容的默认策略

CSP的源包括:

  • *:允许任何URL
  • 'self':允许服务页面的源
  • 'none':不允许任何源
  • host:允许指定的互联网主机
  • 'unsafe-inline':允许内联脚本
  • 'nonce-[base64-value]':允许带有特定一次性标识符的内联脚本

开发者可以根据需要选择合适的指令和源来构建CSP策略。

创建CSP中间件

为了简化CSP策略的设置,可以创建一个可重用的中间件。以下是一个简单的示例,展示了如何创建CSP中间件:

public sealed class CspOptions { public List<string> Defaults { get; set; } = new List<string>(); public List<string> Scripts { get; set; } = new List<string>(); public List<string> Styles { get; set; } = new List<string>(); public List<string> Images { get; set; } = new List<string>(); public List<string> Fonts { get; set; } = new List<string>(); public List<string> Media { get; set; } = new List<string>(); } public sealed class CspOptionsBuilder { private readonly CspOptions options = new CspOptions(); internal CspOptionsBuilder() { } public CspDirectiveBuilder Defaults { get; set; } = new CspDirectiveBuilder(); public CspDirectiveBuilder Scripts { get; set; } = new CspDirectiveBuilder(); public CspDirectiveBuilder Styles { get; set; } = new CspDirectiveBuilder(); public CspDirectiveBuilder Images { get; set; } = new CspDirectiveBuilder(); public CspDirectiveBuilder Fonts { get; set; } = new CspDirectiveBuilder(); public CspDirectiveBuilder Media { get; set; } = new CspDirectiveBuilder(); internal CspOptions Build() { this.options.Defaults = this.Defaults.Sources; this.options.Scripts = this.Scripts.Sources; this.options.Styles = this.Styles.Sources; this.options.Images = this.Images.Sources; this.options.Fonts = this.Fonts.Sources; this.options.Media = this.Media.Sources; return this.options; } } public sealed class CspDirectiveBuilder { internal CspDirectiveBuilder() { } internal List<string> Sources { get; set; } = new List<string>(); public CspDirectiveBuilder AllowSelf() => Allow("'self'"); public CspDirectiveBuilder AllowNone() => Allow("none"); public CspDirectiveBuilder AllowAny() => Allow("*"); public CspDirectiveBuilder Allow(string source) { this.Sources.Add(source); return this; } } public sealed class CspMiddleware { private const string HEADER = "Content-Security-Policy"; private readonly RequestDelegate next; private readonly CspOptions options; public CspMiddleware(RequestDelegate next, CspOptions options) { this.next = next; this.options = options; } public async Task Invoke(HttpContext context) { context.Response.Headers.Add(HEADER, GetHeaderValue()); await this.next(context); } private string GetHeaderValue() { var value = ""; value += GetDirective("default-src", this.options.Defaults); value += GetDirective("script-src", this.options.Scripts); value += GetDirective("style-src", this.options.Styles); value += GetDirective("img-src", this.options.Images); value += GetDirective("font-src", this.options.Fonts); value += GetDirective("media-src", this.options.Media); return value; } private string GetDirective(string directive, List<string> sources) => sources.Count > 0 ? $"{directive} {string.Join(" ", sources)};" : ""; } public static class CspMiddlewareExtensions { public static IApplicationBuilder UseCsp(this IApplicationBuilder app, Action<CspOptionsBuilder> builder) { var newBuilder = new CspOptionsBuilder(); builder(newBuilder); var options = newBuilder.Build(); return app.UseMiddleware<CspMiddleware>(options); } }

通过上述代码,可以在Startup类中配置CSP中间件,从而实现CSP策略的设置。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485