This article shows how to improve the security of an ASP.NET Core Razor Page application by adding security headers to all HTTP Razor Page responses. The security headers are added using the NetEscapades.AspNetCore.SecurityHeaders Nuget package from Andrew Lock. The headers are used to protect the session, not for authentication. The application is authenticated using Open ID Connect, the security headers are used to protected the session.
Blogs in this series
Improving application security in ASP.NET Core Razor Pages using HTTP headers – Part 1
Improving application security in Blazor using HTTP headers – Part 2
Improving application security in an ASP.NET Core API using HTTP headers – Part 3
The NetEscapades.AspNetCore.SecurityHeaders and the NetEscapades.AspNetCore.SecurityHeaders.TagHelpers Nuget packages are added to the csproj file of the web application. The tag helpers are added to use the nonce from the CSP in the Razor Pages.
What each header protects against is explained really good on the securityheaders.com results view of your test. You can click different links of each validation which takes you to the documentation of each header. The links at the bottom of this post provide some excellent information about what and why of the headers.
The security header definitions are added using the HeaderPolicyCollection class. I added this to a separate class to keep the Startup class small, where the middleware is added. I passed a boolean parameter into the method which is used to add or remove the HSTS header. We might not want to add this to local development and block all non HTTPS requests to localhost.
The policy defined in this demo is for Razor Page applications with as much blocked as possible. You should be able to re-use this in your projects.
The COOP (Cross Origin Opener Policy), COEP (Cross Origin Embedder Policy), CORP (Cross Origin Resource Policy) headers are relatively new. You might need to update you existing application deployments with these. The links at the bottom of the post provide information about these headers in detail and I would recommend reading these.
var policy = new HeaderPolicyCollection()
builder.AddStyleSrc().Self(); // .UnsafeInline();
// maxage = one year in seconds
policy.AddStrictTransportSecurityMaxAgeIncludeSubDomains(maxAgeInSeconds: 60 * 60 * 24 * 365);
In the Startup class, the UseSecurityHeaders method is used to apply the HTTP headers policy and add the middleware to the application. The env.IsDevelopment() is used to add or not to add the HSTS header. The default HSTS middleware from the ASP.NET Core templates was removed from the Configure method as this is not required.
The server header can be removed in the program class if using Kestrel. If using IIS, you probably need to use the web.config to remove this.
options.AddServerHeader = false)
We want to apply the CSP nonce to all our scripts in the Razor Pages. We can add the NetEscapades.AspNetCore.SecurityHeaders namespace to the _ViewImports.cshtml file.
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
In the Razor Page _Layout, the CSP nonce can be used. I had to get the nonce from the HttpContext and add this to all scripts. This way, the scripts will be loaded. If the nonce does not match or is not applied to the script, it will not be loaded due to the CSP definition. I’ll ping Andrew Lock to see if the tag helper could be used directly.
<script src=”~/lib/jquery/dist/jquery.min.js” nonce=”@nonce”></script>
<script src=”~/lib/bootstrap/dist/js/bootstrap.bundle.min.js” nonce=”@nonce”></script>
<script src=”~/js/site.js” asp-append-version=”true” nonce=”@nonce”></script>
@await RenderSectionAsync(“Scripts”, required: false)
The Http security headers can be tested using https://securityheaders.com
I used ngrok to test this before I deployed the application. The Security headers scans the web application and returns a really neat summary to what headers you have and how good it finds them. Each header has a link to a excellent documentation, blog on Scott Helme‘s website https://scotthelme.co.uk
The CSP can be tested using the https://csp-evaluator.withgoogle.com from google. The CSP evaluator gives an excellent summary and also suggestions how to improve the CSP.
The Razor Page application security can be much improved by added the headers to the application. The NetEscapades.AspNetCore.SecurityHeaders Nuget package makes it incredibly easy to apply this. I will create a follow up blog with a policy definition for a Blazor application and also a for an Web API application.
If the application is fully protected without any public views, the follow redirects checkbox on the security headers needs to be disabled as then you only get the results of the identity provider used to authenticate.