"Security concept: digital screen with icon Key, 3d render." Licensed from Shutterstock.

Ensuring encrypted web traffic with Strict Transport Security headers (HSTS)

When you’re ready to ensure that no one visits your site over an insecure connection, the Strict Transport Security header is key.

This isn’t a header to be adopted without sufficient consideration and testing, but once implemented, can be part of reliably guaranteeing that visitors may only traverse your site securely. It instructs the browser that a site is accessible only over SSL, and when set according to the specification, does so in a way that’s effective for at least one year from when a site is visited.

A Consideration

Like the Public Key Pinning header (HPKP) I’ve written about, Strict Transport Security headers (HSTS) are meant to be long-lived. Accordingly, there’s a serious chance of accidentally rendering a domain unreachable over HTTP connections before it’s ready to be SSL-only.

If you aren’t redirecting HTTP traffic now, start with that and come back to this post in a few weeks. After several weeks of SSL-only traffic without the HSTS header, you should be ready to make this addition.

As I noted, the HSTS header is meant to have a long duration. The specification calls for an age of at least one year: https://tools.ietf.org/html/rfc6797. Before jumping in with a duration of 31,536,000 seconds, though, it’s worth testing with a shorter interval.

Implementing the header

Unlike HSTS, Strict Transport Security headers aren’t domain-specific, making their introduction much simpler.

To start, decide if subdomains should be subject to the HSTS header alongside the primary domain. Much like the HPKP, HSTS uses an includeSubDomains directive.

Next, we’ll build the header starting with a one-hour duration. As long as you’ve been successfully redirecting HTTP traffic, the shorter duration shouldn’t matter, but it does provide a safety mechanism by allowing for a fairly-quick reversal. One could reduce the header duration even further, but if that seems warranted, this header shouldn’t be considered; it serves no purpose if it isn’t long-lived.

Strict-Transport-Security: max-age=3600;

If subdomains should be supported:

Strict-Transport-Security: max-age=3600; includeSubDomains

If you’re unsure how to add the header in nginx or Apache, my post about HPKP offers guidance.

Once the header is implemented, use a tool like Qualys SSL Server Test to check the result (see External tools for checking my configurations for more of the tools I use).

As long as the Qualys test passes and you’re ready to commit to SSL-only traffic, increase the duration to the specification-recommended one year, with the includeSubDomains directive as needed:

Strict-Transport-Security: max-age=31536000[; includeSubDomains]

preload: HTTPS permanence

After the header has been in place for several weeks (or months, depending on your traffic) without major issues, there is one final directive to consider.

Before proceeding, know that the following discussion is relevant only if you added the includeSubDomains directive in the last section. If you can’t set HSTS on all subdomains, you should not set the preload directive!

HSTS is a “trust on first use” mechanism–it’s effective only after the browser first receives the HSTS header from the server. Fortunately, the IETF specification provides a way for the browser to know initially that a site is only available securely.

Through an approach called preload, a website can declare that it is only accessible via HTTPS; in conjunction with a list discussed below, the browser itself will upgrade any HTTP requests to HTTPS before the server is contacted. Bear in mind that this doesn’t negate the need for server-side redirects, as browsers are the only clients that currently obey HSTS.

The preload portion of the HSTS specification is bifurcated. One part is predicated on an addition to the header sent by your webserver. Its parallel is dependent upon browser makers.

To start, append the preload directive to the end of your HSTS header:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

This addition tells browsers that the domain allows preloading, rather than ceding that control to those generating the lists, protecting against inadvertent inclusion in preloading.

Once a domain supports preloading, major browsers must add the domain to their supported lists. Fortunately, Google makes this very simple: https://hstspreload.appspot.com/. Through that site, you can submit your domain for inclusion in all major browsers. While Google is maintaining the list, Firefox, Safari, IE 11, and Microsoft Edge all use Google’s data.