ASP.NET How to use CSP header against XSS attack in core

Time:2020-5-28

Content security policy (CSP) is an added security layer that helps detect and mitigate certain types of attacks, including cross site scripting (XSS) and data injection attacks. These attacks are used for everything from data theft to site destruction or malware distribution (deep CSP)

In short, CSP is a way for web pages to control which resources are allowed to load. For example, a page can explicitly declare that JavaScript, CSS, and image resources are allowed to load from it. This helps prevent issues such as cross site scripting (XSS) attacks.

It can also be used to restrict protocols, such as content loaded over HTTPS. CSP is implemented through headers in the content security policy HTTP response.

To enable CSP, you need to configure the web server to return the content security policy HTTP header. So in this article, we will try to add CSP to ASP.NET In the core application.


app.Use(async (ctx, next) =>
  {
  ctx.Response.Headers.Add("Content-Security-Policy",
    "default-src 'self'; report-uri /cspreport");
  await next();
  });

Introduce the CDN file in home / index, and then we launch the project to see what happens!

Run and watch for errors. When loading a page, the browser refuses to load from a remote source.

 

So we can organize CSP to control our white list. In the configuration, we need to fill in the source and content. The following are the commonly used restricted options.

Source:

*: allow any web address.
‘self’: allows the source of the provided page. Note that single quotes are required.
“None”: no source is allowed. Note that single quotes are required.
Host: allows the specified Internet host by name or IP address. Wildcards (asterisk characters) can be used to include all subdomains, such as http: / * foo.com
‘unsafe line’: allow inline scripts
‘nonce – [Base64 value]’: allows inline scripts (once used numbers) with a specific nonce. Nonce should be encrypted and unique for each HTTP request / response.

Instruction:

Script SRC: define a valid javascript source
Style SRC: defines a valid source for style sheets
IMG SRC: define valid image source
Connect SRC: define a valid source for Ajax calls
Font SRC: define a valid font source
Object SRC: define the effective source of < Object >, < embed > and < applet > elements
Media SRC: define valid audio and video sources
Form action: defines a valid source that can be used as an HTML < form > action.
Default SRC: Specifies the default policy for loading content

We can encapsulate and add CSP headers in reusable middleware. Here is an example to get you started. You can expand it as needed. First, create a class to hold the source.


public 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>();
 }

Developing a middleware must require a constructor, which will be used to inject. Net core into the running environment.


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; 
  } 
 }

OK, let’s create a middleware.


namespace XSSDefenses.XSSDefenses.MiddlerWare
{
 public sealed class CspOptionMiddlerWare
 {
  private const string HEADER = "Content-Security-Policy";
  private readonly RequestDelegate next;
  private readonly CspOptions options;

  public CspOptionMiddlerWare(
   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)}; " : "";
 }
}

And set its extension method.


namespace XSSDefenses.XSSDefenses.Extensions
{
 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<CspOptionMiddlerWare>(options);
  }
 }
}

We can now configure the middleware in the startup class.


app.UseCsp(builder =>
   {
    builder.Styles.AllowSelf()
    .Allow(@"https://ajax.aspnetcdn.com/");
   });

Start Discovery and observe network resources. The browser already allows local and remote resources.

summary

The above is the whole content of this article. I hope that the content of this article has some reference learning value for your study or work. Thank you for your support for developepaer.