When creating a new ASP.NET Core application, you get a set of middleware that performs typical web application duties. Some include serving static assets, routing, HTTPS redirection, and exception handling. Folks looking will also notice a middleware registration of the app.UseHsts() found in every ASP.NET Core app.

What is HSTS, why would you want it, and how do you configure the HSTS options in ASP.NET Core? Let’s find out.

What is HSTS?

HSTS (HTTP Strict Transport Security) is a method by which your application server can tell clients to use a secure connection when sending requests. As you may know, HTTP is unsecured communication, while HTTPS uses encryption to improve users’ privacy and security. Applications can transition user sessions from HTTP and HTTPS, and historically, it was very common to move from an unsecured part of a website to a secured section. For example, shopping sites used to display store items over HTTP and then only use HTTPS for the checkout process.

This still happens in ASP.NET Core today, but typically only on the first request to the application. You may notice this line somewhere in your ASP.NET Core pipeline definition.

app.UseHttpsRedirection();

If a user visits your application using http://, the ASP.NET Core middleware will attempt to rewrite the request to target https://. This is all good and secure, well, except for that first request, and that’s the crucial part. There’s still some unsecured communication occurring, which can be an issue depending on what is included in that initial request.

With HSTS, we want to communicate several aspects to any client accessing our application:

  1. Always communicate using HTTPS, no matter what.
  2. If includeSubdomains is present we also mean all subdomains.
  3. If preload is set, the browser will always make HTTPS requests, even on the first request.
  4. The max-age of the policy, which can be measured in seconds to years.

The preload value is the most interesting, as this is used by browser vendors to create a known list of sites serving only experiences over HTTPS. This allows the browser to switch to HTTPS before the first request. A browser will never communicate with your application over HTTP, even if your server supports it.

While you may be tempted to turn on HSTS and the preload functionality immediately, you must be mindful of what’s expected of your application before deploying this feature.

  1. Serve and maintain a valid certificate
  2. Redirect from HTTP to HTTPS on the same host
  3. Serve all subdomains over HTTPS
  4. Serve an HSTS header with a max-age of 1 year, includeSubdomains, and include the preload key.
  5. Redirect responses must also contain the HSTS header.
`Strict-Transport-Security:` `max-age=63072000; includeSubDomains; preload`

And finally, you can verify that you’ve satisfied all the requirements by going to https://hstspreload.org.

In summary, HSTS allows you to tell browser vendors that you want an added level of security by having all communication occur over encrypted communication and that requests or responses should never be unsecured. In short, enforce HTTPS.

HSTS in ASP.NET Core

Let’s get back to ASP.NET Core. You’ve likely seen this line in your applications but never clicked through the link in the comment.

// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();

Why is the default value 30 days, and why should you consider changing it for production scenarios?

30 days is a nice round number, just long enough to be helpful but not so long that if you make a mistake, it will take forever for browser vendors to resolve. That said, you should change the value for production. The HSTS preload guidance is a gradual smoke test and will likely take a few application deployments to work through.

Start with a low max-age of 5 minutes, test your site, then graduate to 1 week and to 1 month.

max-age=2592000; includeSubDomains

Along the way, test your site for errors or issues related to HTTPS traffic. Standard HTTP to HTTPS issues include static assets and CDN dependencies. When you feel confident you’ve squashed all your issues, you can add the preload value and increase the max-age to 2 years.

You’ll need to configure the HstsOptions object registered in your ASP.NET Core services collection to work up to this.

builder.Services.Configure<HstsOptions>(o =>
{
    o.Preload = true;
    o.MaxAge = new TimeSpan(730 /* 2 years */);
    o.IncludeSubDomains = true;
});

The next time your site is crawled by the major browser providers (Google, Mozilla, or Microsoft), you’ll be added to the preload list hard-coded into browsers.

If you’re running a multi-tenant site and need to exclude different tenants from a particular policy, you can also set the ExcludeHosts property.

builder.Services.Configure<HstsOptions>(o =>
{
    o.Preload = true;
    o.MaxAge = new TimeSpan(730 /* 2 years */);
    o.IncludeSubDomains = true;
    o.ExcludedHosts.Add("example.com");
    o.ExcludedHosts.Add("www.example.com");
});

Just note that if you exclude a subdomain from a top-level domain that opts into HSTS, you can’t get the preload capability since you’ve not satisfied the requirements.

Should I turn on HSTS?

HSTS is an added layer of security that can prevent man-in-the-middle attacks from protocol downgrades and cookie hijacking. That said, ASP.NET Core has mechanisms to secure cookies, such as Data Protection encryption and browser-handling hints such as Secure, HttpOnly, and SameSite. As long as you don’t change those values, you’ll be following best practices. That said, always consult an actual security professional and perform security audits periodically.

HSTS can be annoying if you accidentally enable it in a development environment that may not have a certificate, but in most production environments, you should have a certificate.

In general, yes, you should enable it, but be mindful when and where you enable it, as it can be challenging to get browsers to refresh the policy.

Conclusion

You now know a little bit more about HSTS, why it’s included in your ASP.NET Core application, and how and when to configure it. HSTS is an additional layer of security specifically designed to keep all communication over HTTPS, including those initial requests. That said, you’ll need to put in the work to get that preload functionality and plan for weeks of deployments, testing, and audits to make sure everything is working smoothly.

As always, thanks for reading, and cheers.

References