HTTP Strict Transport Security (HSTS) prevents a variety of different attacks based around circumventing SSL protection. Implementing HSTS is an essential strategy for helping to secure your website from malicious attacks. It is one of the components we test and monitor as part of every technical website audit.

What is HSTS?

HTTP Strict Transport Security tells a web browser that it should never load your site using HTTP and should automatically convert all attempts to access your website using HTTP to HTTPS requests instead. HSTS consists of a single HTTP header, Strict-Transport-Security, sent by the server with the resource. It tells the browser that changing the protocol from HTTP to HTTPS in a URL will function correctly, is more secure and asks the browser to do it for every future request, until a specified expiry time.

How does HSTS work?

If your website accepts a connection through HTTP and redirects to HTTPS, visitors might initially communicate with the non-encrypted version of your site before being redirected. If, for example, the visitor types http://www.yourwebsite.com/ or even just yourwebsite.com this creates an opportunity for a man-in-the-middle attack. An exploited redirect can divert visitors to a malicious site instead of the secure version of your website.

Example scenario

You may be thinking “I already 301 redirect from HTTP to HTTPS. Isn’t that safe enough?” In short, no. Let’s say, for example, that you’re in a café and have connected your laptop to a free WiFI access point so that you can check your bank account balance and pay a few bills. Unbeknown to you, the access point is a hacker’s laptop, and they are intercepting your initial HTTP request and redirecting you to a clone of your bank’s website instead of the real thing. When you attempt to log in, your private data is exposed to the hacker and captured.

HTTP Strict Transport Security solves this problem as long as you have visited your bank’s website once using HTTPS and provided they use Strict Transport Security. If so, your web browser will know to use HTTPS automatically. It will prevent any potential man-in-the-middle attack that could have exploited an initial HTTP request.

How the web browser manages HSTS

It’s important to understand that HSTS only works on a browser after your website is accessed using HTTPS. The first time your site is accessed using HTTPS, it returns the Strict-Transport-Security header. The web browser records this information so that all future attempts to load the site will automatically use HTTPS instead of HTTP. It remains so until the expiry time specified in the HSTS header elapses. After that time, the next attempt to load your website using HTTP will proceed normally instead of automatically using HTTPS. If the Strict-Transport-Security is still in place, the web browser will receive the header with a new expiry time, and all future requests will once again be via HTTPS only.

Should I implement HSTS?

In general, we’d recommend always implementing HSTS on your website if you’re an e-commerce store or if your site has a secure login area for customers. It’s essential to consider the use of HSTS in combination with a TLS/SSL certificate to protect cardholder data, logins and private information. If you’re running a small blog or personal website with no personal data stored, then HSTS isn’t essential. However, Google uses many factors to decide where a site should rank in search results. Among these are security and load time — HSTS is beneficial for both. Given the relative simplicity of enabling HSTS on your website, we recommend that website owners implement it as part of their standard website configuration.

What you need to know about HTTP Strict Transport Security (HSTS)

The Strict-Transport-Security header contains three possible directives, two of which are optional.

max-age=<expire-time>
The time, in seconds, that the browser should remember that a site is only to be accessed using HTTPS.
includeSubDomains | Optional
If this optional parameter is specified, this rule applies to all of the site’s subdomains as well.
preload | Optional
Not officially part of the specification. See Preloading Strict Transport Security for details.

Preloading Strict Transport Security

The preload directive can potentially cause a lot of headaches, so it’s essential to understand what this directive does before adding Strict Transport Security headers on your website. It’s great to support HSTS preloading as a best practice. However, site operators who enable HSTS should know about the long-term consequences of preloading before they turn it on for a given domain.

HSTS preloading is a function built into web browsers based on a global list of HSTS-enabled hosts. The file is compiled by The Chromium Projects and embedded into the Google Chrome web browser. Other browsers maintain records based on the Chrome list, including Firefox, Safari, Opera, Edge and Internet Explorer.

If a domain is on the HSTS Preload List, the web browser does not depend on the HSTS headers to enforce Strict Transport Security policy. Instead, the browser is immediately aware of the requirement to use HTTPS only before the connection even takes place. HTTPS gets enforced regardless of any headers that might be served by the website.

Benefits of preloading HSTS

Remember the earlier example about connecting to your bank using a WiFi hotspot at a café? You might recall that HSTS is only valid until the expiry time in the HSTS header elapses. Once it has passed, an HTTP connection is possible to a website before being redirected to HTTPS and obtaining the HSTS header with a new expiry time. See the problem? It provides a window of opportunity for your traffic to be intercepted during the HTTP connection and redirected to a malicious site. The HSTS preload list addresses this by enforcing HTTPS connections only to domains in the list, without the need to first check for HSTS headers.

Cautions about preloading HSTS

Undoing inclusion in the HSTS preload list is not simple. Domains are removable, but records are embedded into web browsers and can take months for the change to reach users. We recommend that you do not include the preload directive by default without carefully considering the implications of this. Removal is slow and painful and could render non-SSL subdomains inaccessible to users until the removal process is complete. Don’t request inclusion unless you’re sure that you can support HTTPS for your entire site and all its subdomains in the long term.

Removing a domain from the HSTS preload list

If a preloaded site sends a valid HSTS header without the preload directive, it is requesting removal from the preload list. Once you’ve removed the preload directive, we’d also suggest using the removal form if you have satisfied the following requirements:

  1. Be preloaded or pending preload through hstspreload.org.
  2. Serve HTTPS with a valid certificate.
  3. Send a valid HSTS header. The header must not contain the preload directive.

Note that a preload list domain removal may take 6-12 weeks to reach most Chrome users, and may take longer for other browsers.

HSTS requirements

Your website must:

  1. Serve a valid SSL certificate.
  2. Redirect from HTTP to HTTPS on the same host, if you are listening on port 80.
  3. Serve all subdomains over HTTPS. In particular, you must support HTTPS for the www subdomain if a DNS record for that subdomain exists.

Note that the Strict Transport Security specification is for HTTPS connections only. Do not specify HSTS headers on HTTP connections — the HSTS headers will get picked up when the 301 redirect instructs the web browser to connect using HTTPS.

If you are considering adding your domain to the HSTS preload list then you must serve an HSTS header on the base domain for HTTPS requests:

  1. The max-age must be at least 31536000 seconds (1 year).
  2. The includeSubDomains directive must be specified.
  3. The preload directive must be specified.
  4. If you are serving an additional redirect from your HTTPS site, that redirect must still have the HSTS header (rather than the page it redirects to).

Deployment recommendations

  1. Due to the includeSubDomains directive, we recommend that your primary domain be a non-www domain. It ensures that all subdomains, including the www domain, are covered by HSTS policy. HSTS implementation becomes more difficult if you redirect from a non-www domain to a www domain.
  2. Test all subdomains on your website and ensure they all work properly over HTTPS. Using yourdomain.com as an example, this would include testing to ensure that all of the following URLs correctly redirect to https://yourdomain.com:
    • http://www.yourdomain.com
    • https://www.yourdomain.com
    • http://yourdomain.com
  3. Add the Strict-Transport-Security header to all HTTPS responses and ramp up the max-age in stages, using the following header values:
    • 5 minutes: max-age=300; includeSubDomains
    • 1 week: max-age=604800; includeSubDomains
    • 1 month: max-age=2592000; includeSubDomains
  4. During each stage above, test for broken pages and monitor your site metrics (traffic, revenue). Having a technical website audit running against your site is a simple way to identify any problems without having to test every page on your site manually.
  5. Once you are confident there are no issues, increase the max-age to 2 years (this is the maximum time that can be specified) and submit your site to the preload list:
    max-age=63072000; includeSubDomains; preload

How to implement HTTP Strict Transport Security (HSTS)

As per the Strict Transport Security specification, do not specify HSTS headers on HTTP connections — the HSTS headers will get picked up when the 301 redirect instructs the web browser to connect using HTTPS.

Also, ensure that your 301 redirects perform the HTTP to HTTPS redirection before the www to non-www redirection.

Example HSTS implementation for the Apache HTTP Server

Some suggest specifying env=HTTPS at the end of the header to ensure HSTS is only on HTTPS connections, like this:

Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" env=HTTPS

However, we’ve found this method to be unreliable in many instances.

We recommend wrapping the header in <if "%{HTTPS} == 'on'">...</if> instead.

Add the following to the .htaccess file, usually found in the root folder of your website:

# BEGIN: Enable HSTS for HTTPS connections
<if "%{HTTPS} == 'on'">
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
</if>
# END: Enable HSTS for HTTPS connections