Adding HTTP Headers to improve Security in an ASP.NET MVC Core application

This article shows how to add headers in a HTTPS response for an ASP.NET Core MVC application. The HTTP headers help protect against some of the attacks which can be executed against a website. securityheaders.io is used to test and validate the HTTP headers as well as F12 in the browser. NWebSec is used to add most of the HTTP headers which improve security for the MVC application. Thanks to Scott Helme for creating securityheaders.io, and André N. Klingsheim for creating NWebSec.

Code: https://github.com/damienbod/AspNetCoreHybridFlowWithApi

History

2018-11-10 Updated to .NET Core 2.2, small corrections

2018-05-07 Updated to .NET Core 2.1 preview 2, new Identity Views, 2FA Authenticator, IHttpClientFactory, bootstrap 4.1.0

2018-02-09: Updated, added feedback from different sources, removing extra headers, add form actions to the CSP configuration, adding info about CAA.

A simple ASP.NET Core MVC application was created and deployed to Azure. securityheaders.io can be used to validate the headers in the application. The deployed application used in this post can be found here: https://webhybridclient20180206091626.azurewebsites.net/status/test

Testing the default application using securityheaders.io gives the following results with some room for improvement.

Fixing this in ASP.NET Core is pretty easy due to NWebSec. Add the NuGet package to the project.

<PackageReference Include="NWebsec.AspNetCore.Middleware" Version="2.0.0" />

Or using the NuGet Package Manager in Visual Studio

Note

All the NWebSec code configurations are added to the Startup.cs class in the Configure method.

Add the Strict-Transport-Security Header

By using HSTS, you can force that all communication is done using HTTPS. If you want to force HTTPS on the first request from the browser, you can use the HSTS preload: https://hstspreload.appspot.com

app.UseHsts(hsts => hsts.MaxAge(365).IncludeSubdomains());

https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security

Add the X-Content-Type-Options Header

The X-Content-Type-Options can be set to no-sniff to prevent content sniffing.

app.UseXContentTypeOptions();

https://www.keycdn.com/support/what-is-mime-sniffing/

https://en.wikipedia.org/wiki/Content_sniffing

Add the Referrer Policy Header

This allows us to restrict the amount of information being passed on to other sites when referring to other sites. This is set to no referrer.

app.UseReferrerPolicy(opts => opts.NoReferrer());

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy

Scott Helme write a really good post on this:
https://scotthelme.co.uk/a-new-security-header-referrer-policy/

Add the X-XSS-Protection Header

The HTTP X-XSS-Protection response header is a feature of Internet Explorer, Chrome and Safari that stops pages from loading when they detect reflected cross-site scripting (XSS) attacks. (Text copied from here)

app.UseXXssProtection(options => options.EnabledWithBlockMode());

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection

Add the X-Frame-Options Header

You can use the X-frame-options Header to block iframes and prevent click jacking attacks.

app.UseXfo(options => options.Deny());

Add the Content-Security-Policy Header

Content Security Policy can be used to prevent all sort of attacks, XSS, click-jacking attacks, or prevent mixed mode (HTTPS and HTTP). The following configuration works for ASP.NET Core MVC applications, the mixed mode is activated, styles can be read from unsafe inline, due to the razor controls, or tag helpers, and everything can only be loaded from the same origin.

app.UseCsp(opts => opts
	.BlockAllMixedContent()
	.StyleSources(s => s.Self())
	.StyleSources(s => s.UnsafeInline())
	.FontSources(s => s.Self())
	.FormActions(s => s.Self())
	.FrameAncestors(s => s.Self())
	.ImageSources(s => s.Self())
	.ScriptSources(s => s.Self())
);

Due to this CSP configuration, the public CDNs need to be removed from the MVC application which are per default included in the dotnet template for an ASP.NET Core MVC application.

https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP

NWebSec configuration in the Startup

//Registered before static files to always set header
app.UseHsts(hsts => hsts.MaxAge(365).IncludeSubdomains());
app.UseXContentTypeOptions();
app.UseReferrerPolicy(opts => opts.NoReferrer());
app.UseXXssProtection(options => options.EnabledWithBlockMode());
app.UseXfo(options => options.Deny());

app.UseCsp(opts => opts
	.BlockAllMixedContent()
	.StyleSources(s => s.Self())
	.StyleSources(s => s.UnsafeInline())
	.FontSources(s => s.Self())
	.FormActions(s => s.Self())
	.FrameAncestors(s => s.Self())
	.ImageSources(s => s.Self())
	.ScriptSources(s => s.Self())
);

app.UseStaticFiles();

When the application is tested again, things look much better.

Or view the headers in the browser, for example F12 in Chrome, and then the network view:

Here’s the securityheaders.io test results for this demo.

https://securityheaders.io/?q=https%3A%2F%2Fwebhybridclient20180206091626.azurewebsites.net%2Fstatus%2Ftest&followRedirects=on

Removing the extra infomation from the Headers

You could also remove the extra information from the HTTPS headers, for example X-Powered-By, or Server, so that less information is sent to the client.

Remove the server headers from the kestrel server, by using the UseKestrel extension method.

.UseKestrel(c => c.AddServerHeader = false)

Add a web.config to your project with the following settings:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.web>
    <httpRuntime enableVersionHeader="false"/>
  </system.web>
  <system.webServer>
    <security>
      <requestFiltering removeServerHeader="true" />
    </security>
    <httpProtocol>
      <customHeaders>
        <remove name="X-Powered-By"/>
      </customHeaders>
    </httpProtocol>
  </system.webServer>
</configuration>

Now by viewing the response in the browser, you can see some unrequired headers have been removed.


Further steps in hardening the application:

Use CAA

You can fix your domain to a selected amount of authorities. You can control the authorities which can issue the certs for your domain. This reduces the risk, that another cert authority produces a cert for your domain to a different person. This can be checked here:

https://toolbox.googleapps.com/apps/dig/

Or configured here:
https://sslmate.com/caa/

Then add it to the hosting provider.

Use a WAF

You could also add a WAF, for example to only expose public URLs and not private ones, or protect against DDoS attacks.

Certificate testing

The certificate should also be tested and validated.

https://www.ssllabs.com is a good test tool.

Here’s the result for the cert used in the demo project.

https://www.ssllabs.com/ssltest/analyze.html?d=webhybridclient20180206091626.azurewebsites.net

I would be grateful for feedback, or suggestions to improve this.

Links:

https://securityheaders.io

https://docs.nwebsec.com/en/latest/

https://github.com/NWebsec/NWebsec

https://www.troyhunt.com/shhh-dont-let-your-response-headers/

https://anthonychu.ca/post/aspnet-core-csp/

https://rehansaeed.com/content-security-policy-for-asp-net-mvc/

https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security

https://www.troyhunt.com/the-6-step-happy-path-to-https/

https://www.troyhunt.com/understanding-http-strict-transport/

https://hstspreload.appspot.com

https://geekflare.com/http-header-implementation/

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options

https://docs.microsoft.com/en-us/aspnet/core/tutorials/publish-to-azure-webapp-using-vs

https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning

https://toolbox.googleapps.com/apps/dig/

https://sslmate.com/caa/

Advertisements

4 comments

  1. […] Adding HTTP Headers to improve Security in an ASP.NET MVC Core application (Damien Bowden) […]

  2. […] Adding HTTP Headers to improve Security in an ASP.NET MVC Core application – Damien Bowden […]

  3. […] Adding HTTP Headers to improve Security in an ASP.NET MVC Core application (Damien Bowden) […]

  4. […] only explains how to add custom header on asp.net mvc using IIS. You can checkout a blogpost by Damienbod which explains how to do it on asp.net core MVC aplication by configuring the Startup […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: