Adding security headers to prevent XSS and MiTM attacks in .Net Core

As a developer, we need to consider security when designing and building web applications. HTTP Response Headers allow server to pass additional information to instruct browsers how to handle sensitive data and content of the application and/or from external or untrusted sources. HTTP response security headers provide an extra layer of protection to help mitigating vulnerabilities and attacks.

One way to add those security headers from .Net Core application is by writing a custom action filter that would be executed before serving any response from the application.

Below is a example of the custom attribute:

public class SecurityHeadersAttribute : ActionFilterAttribute
{
private readonly string transport_security_policy = "Strict-Transport-Security: max-age=31536000; includeSubDomains";
private readonly string content_type_policy = "nosniff";
private readonly string frame_policy = "sameorigin";
private readonly string referrer_policy = "no-referrer";
private readonly string xss_protection_policy = "X-XSS-Protection: 1; mode=block";
private readonly string content_security_policy = "default-src 'self' {0}; object-src 'none'; frame-ancestors 'none'; base-uri 'self';";
private readonly string _sources;
public SecurityHeadersAttribute(params string[] trustedSources)
{
_sources = trustedSources?.Join(" ");
}
public override void OnResultExecuting(ResultExecutingContext context)
{
var result = context.Result;
if (result is ViewResult)
{
//https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
AddResponseHeader(context, "Strict-Transport-Security", transport_security_policy);
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
AddResponseHeader(context, "X-Content-Type-Options", content_type_policy);
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
AddResponseHeader(context, "X-Frame-Options", frame_policy);
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
AddResponseHeader(context, "Referrer-Policy", referrer_policy);
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
var csp = string.Format(content_security_policy, _sources);
AddResponseHeader(context, "Content-Security-Policy", csp); // For standards compliant browsers
AddResponseHeader(context, "X-Content-Security-Policy", csp); // For IE
//https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection
AddResponseHeader(context, "X-XSS-Protection", xss_protection_policy);
}
}
/// <summary>
/// Appends a header to current response with specified value
/// </summary>
/// <param name="context"></param>
/// <param name="key"></param>
/// <param name="value"></param>
private void AddResponseHeader(ResultExecutingContext context, string key, string value)
{
if (!context.HttpContext.Response.Headers.ContainsKey(key))
{
context.HttpContext.Response.Headers.Add(key, value);
}
}
}
To apply this globally for all responses, we can add this to the Startup class as in below:

public void ConfigureServices(IServiceCollection services)
{
// configure app services here...
// add security header as global filter
services.AddMvc(config => config.Filters.Add(new SecurityHeadersAttribute()));
}
view raw Startup.cs hosted with ❤ by GitHub
To apply trusted source for any particular action:

[HttpGet]
[SecurityHeaders("https://www.google.com/recaptcha/","https://www.gstatic.com/recaptcha/")]
public async Task<IActionResult> Login(string returnUrl)
{
var loginViewModel = await _account.BuildLoginViewModelAsync(returnUrl);
return View(loginViewModel);
}

And here is the outcome:







HAPPY CODING 👌

Comments

Post a Comment

Popular posts from this blog

Microsoft.IdentityModel.Protocols.OpenIdConnectProtocolInvalidNonceException

Executing synchronous methods asynchronously