Using a Content Security Policy (CSP) To Prevent Cross Site Scripting Vulnerabilities.

Last week while attending IT/Dev Connections, I had the opportunity to sit in a session on web security with Christian Wenz. He focused on the use of Content Security Policy headers to prevent cross site scripting vulnerabilities. It’s a great concept for an additional layer of security to defend your site. A CSP header controls where a web browser is allowed to load content from and the type of content it is allowed to load. This means you can limit the browser to loading css, javascript or images from your own domain, and block other data, such as a malicious script. There are a few gotchas to consider, which I’ll mention a bit later.

The first step in using a CSP is specifying the policy. It’s really a string that contains a list of policy directives to describe how certain resources should be handled. It could look something like this.

Content-Security-Policy: default-src ‘self’

In this case, the “default-src” is the fallback policy for a resource type that doesn’t have a policy specified. The “self” specifies that allowed content will come from the site’s own origin. If you wanted to allow content from subdomains, they could be added to the directive.

Content-Security-Policy: default-src ‘self’ *.mydomain.com

Multiple directives can be included so you can specify how different content types should be handled. Semicolons are used to delimit the directives. So if you wanted to require that all images be loaded from myCDN.com, you could include a directive for images.

Content-Security-Policy: default-src ‘self’ *.mydomain.com; img-src myCDN.com

Another neat trick is to force all content to be loaded using SSL. Simply include the https:// to the directive.

Content-Security-Policy: default-src https://mydomain.com

So here is the first gotcha…Not all browsers support CSP, but most modern browsers do, and it’s getting better! Remember CSP is part of a layered defense, so don’t rely solely on it.

The next step is to create a MVC filter for the CSP. Filters can be applied globally, on an individual controller, or at the action level.

public class ContentSecurityPolicyFilterAttribute : ActionFilterAttribute
{
     public override void OnActionExecuting(ActionExecutingContext context)
     {
          var response = context.HttpContext.Response;
          response.Headers.Add("Content-Security-Policy",
                               "script-src 'self'; style-src 'self';");
          base.OnActionExecuting(context);
     }
}

[ContentSecurityPolicyFilter]
public IActionResult Index()
{
     return View();
}

Once you have an MVC filter in place, you can begin experimenting with CSP. There are a few ways a “default” policy will affect your website. Inline styles will not be applied. Markup such as this will be rendered in the default color, because the inline style will be blocked by default.

<div class="row">
     <div class="btn btn-default" style="color: red;">In line style test.</div>
</div>

Inline scripts are also blocked by default, so you need to make sure all your javascript is loaded from external files.

<div class="row">
     <div class="btn btn-warning">Mouse over attack.</div>
</div>

In this case, with the CSP in place, the inline javascript will not execute when you move the mouse over the button.

If you don’t like the idea of writing the MVC filters, you could install the NWebsec.MVC NuGet package. It provides a collection of MVC filters for each CSP directive, so you can apply them to controller actions as needed. It currently works for ASP.Net MVC 3/4/5 apps. A new version for ASP.Net Core is in the works.