ASP.NET Core Security Headers

With the help of headers, your website could send some useful information to the browser. Let’s see how it is possible to add more protection to your website.

To add a header for each request, we can use middleware.


Still in the OWASP top 10, there is XSS - Cross-Site Scripting attack. Sure, it helps a lot to encode symbols before displaying text on the website (using any one of the HtmlEncoder, JavaScriptEncoder, and UrlEncoder). And, it’s better never to use @Html.Raw(). But it is also possible to add a header that will inform the browser to stop XSS attack. This kind of header is useful mostly for old browsers.

  1. app.Use(async (context, next) =>  
  2.     {  
  3.         context.Response.Headers.Add("X-Xss-Protection""1");  
  4.         await next();  
  5.     });  

For new browsers, it is better to use CSP. Here is how it is possible to add the CSP header.

  1. app.Use(async (context, next) =>  
  2.     {  
  3.         context.Response.Headers.Add(  
  4.             "Content-Security-Policy",  
  5.             "default-src 'self'; " +  
  6.             "img-src 'self'; " +  
  7.             "font-src 'self'; " +  
  8.             "style-src 'self'; " +  
  9.             "script-src 'self' 'nonce-KIBdfgEKjb34ueiw567bfkshbvfi4KhtIUE3IWF' "+  
  10.             " 'nonce-rewgljnOIBU3iu2btli4tbllwwe'; " +  
  11.             "frame-src 'self';"+  
  12.             "connect-src 'self';");  
  13.         await next();  
  14.     });  

In this example, it is allowed to run scripts.js files only from the current website (that is a meaning of ‘self’). And it is allowed to run 2 specified with “nonce” attribute scripts that are inserted in page inside script tag. For example, if you are using some script like this one inside your page.

  1. <script>  
  2. function showMessage() {  
  3.     alert("Just for demo");  
  4. }   
  5. </script>  

Then, you will be not able to run this script without adding ‘unsafe-inline’ into your CSP definition.

But adding ‘unsafe-inline’ means leaving your website not-protected. So, better move the script into .js file or use a nonce. Just add to your script attribute nonce with some random value. For example,

  1. <script nonce="KUY8VewuvyUYVEIvEFue4vwyiuf"> </script>  

Then, you can add to your CSP script-scr value ‘nonce-KUY8VewuvyUYVEIvEFue4vwyiuf’ and you will be able to run scripts from exactly this <script> section.

‘unsafe-inlne’ is also related to events that are added to your html as attributes. Like onclick, onchange, onkeydown, onfocus. For example, instead of the following onclick event, you should add id or class to your element and call event from <script> or .js file.

  1. <p onclick="showMessage()">Show message</p>  

Like this,

  1. <p id="message-text">Show message</p>  
  3. <script nonce=”KUY8VewuvyUYVEIvEFue4vwyiuf”>  
  4. $(document).ready(function() {  
  5.   $("#message-text") (function() {  
  6.     alert( "Just for demo" );  
  7.   });   
  8. });  
  9. </script>  


By default, it is possible to display your website inside an iframe. But with one small header, it is possible to disallow this. Why? Because someone could display your website inside a frame and place a transparent layer over it. And, the users would be thinking that they are clicking on your website buttons/links but in a real case, they would be clicking on items placed in the transparent layer. And as cookies still could be in the user’s browser, some operation could be authenticated. This kind of attack is called Clickjacking. And, here is a header to protect your website from this attack.

  1. context.Response.Headers.Add("X-Frame-Options""DENY");  

Content sniffing

By the next link File Upload XSS you can find a more or less fresh sample of how it is possible to inject JavaScript into an svg file. And if a file like this would be located on the server that would have content sniffing security enabled, then JavaScript wouldn’t work because svg extension doesn’t correspond to JS content. Hope you believe me now that the next header is required.

  1. context.Response.Headers.Add("X-Content-Type-Options""nosniff");  


One of the headers that is automatically added by browsers is “Referer”. It contains a site from which the user has been transferred. Sometimes, that is convenient for analytics. But sometimes, the URL could contain some private information that is better not to be disclosed. For example, who cares what article a user has edited before:

If you don’t want to allow browsers to display your website as last visited in “Referer” header, please use the Referrer-Policy: no-referrer

Here is an example of all headers in one middleware.

  1. app.Use(async (context, next) =>  
  2.     {  
  3.         context.Response.Headers.Add("X-Xss-Protection""1");  
  4.         context.Response.Headers.Add("X-Frame-Options""DENY");  
  5.         context.Response.Headers.Add("Referrer-Policy""no-referrer");  
  6.         context.Response.Headers.Add("X-Content-Type-Options""nosniff");  
  7.                         context.Response.Headers.Add(  
  8.             "Content-Security-Policy",  
  9.             "default-src 'self'; " +  
  10.             "img-src 'self'; " +  
  11.             "font-src 'self'; " +  
  12.             "style-src 'self'; " +  
  13.             "script-src 'self' 'nonce-KIBdfgEKjb34ueiw567bfkshbvfi4KhtIUE3IWF' "+  
  14.             " 'nonce-rewgljnOIBU3iu2btli4tbllwwe'; " +  
  15.             "frame-src 'self';"+  
  16.             "connect-src 'self';");  
  17.         await next();  
  18.     });  

Sure, you can read information about each one header and change value to something more appropriate for your needs.


For activating Strict-Transport-Security - web security policy mechanism that helps to protect your website from protocol downgrade attacks and cookie hijacking, add the next one to your middleware pipeline (or just don’t remove it),

  1. app.UseHsts();  

This middleware will add “Strict-Transport-Security” header

Removing Server Header

Sometimes, headers could provide some information that is better to hide. To disable the Server header from Kestrel, you need to set AddServerHeader to false. Use UseKestrel() if your ASP.NET Core version is  lower than 2.2 and ConfigureKestrel() if not.

  1. WebHost.CreateDefaultBuilder(args)  
  2.                .UseKestrel(c => c.AddServerHeader = false)  
  3.                .UseStartup<Startup>()  
  4.                .Build();