site logoTune The Web
I've written a book! - click here to view or buy "HTTP/2 in Action" from Manning. Use code 39pollard to get 39% off!

HTTP Strict Transport Security (HSTS)

This page was originally created on and last edited on .

Introduction

HTTPS is the standard way of securing your website traffic, and providing confidence to your users that they are on a legitimate website. However the default for most of the web is still HTTP: if you type in a URL without specifying the protocol (e.g. www.google.com) then the browser will default this to HTTP. Most websites with a HTTPS version will automatically redirect users to this version, but this does give an attacker an opportunity to intercept the traffic and act as a Man in the Middle and keep you on HTTP.

The HTTP Strict Transport Security (HSTS) header states that your website must only be accessed over the HTTPS protocol. So even if a user enters www.tunetheweb.com, the web browser will automatically request https://www.tunetheweb.com. This also has the added advantage of avoiding a redirect - improving the performance of your site. The use of the HSTS header also tells the browser that the use should not be allowed to ignore certificate errors and browse the website anyway. Security expert Ivan Ristić says that "Adding support for HSTS is the single most important improvement you can make for the TLS security of your web sites." and only sites with this setting get an A+ grade in his ssllabs.com scanning tool.

How to set it up

Assuming your site is already all HTTPS, then set up is simply a matter of adding the Strict-Transport-Security HTTP header to your web server and specifying a length of time you want this policy to be in place for. In Apache this can be done with the following config:

Header always set Strict-Transport-Security "max-age=60;"

This will set the header to force use of HTTPS for 60 seconds. It's best to keep the max-age down to low values while testing this, and after initial go-live, to stop blocking other users accidentally.

To test fire up Chrome, hit F12 to view developer tools, go to your website once to load the policy, then visit again using HTTP and you should see something like below:

Chrome Developer Tools showing 307 redirect due to HSTS

You should see that chrome automatically does a 307 internal redirect from HTTP to HTTPS. You can test this website in the same way by visiting http://www.tunetheweb.com, again with developer tools open.

After you're happy it all works increase it to a year or two. Ssllabs.com recommends a 6 month minimum though this site has set a max-age of 2 years (63072000 is the number of seconds in two years: 60*60*24*365*2):

You can also specify an includeSubDomains extra setting so any subdomains also get this setting even if not explicitly set there:

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

This does add extra security - particularly against cookie attacks, but it does depend on your whole domain only ever being server via HTTPS, so here is where you need to be a little more careful as this is potentially quite dangerous. It depends on all subdomains being on HTTPS. While this may seem obvious, this has large consequences if you set it at your top level domain (e.g. tunetheweb.com rather than www.tunetheweb.com) and websites have got it wrong in the past and, with a long expiry, than can spell disaster for your website if an incorrect policy gets loaded in many people's browsers.

The problem is, that's actually easy to do without thinking! For example if you are running a website you should make it accessible by both the top level domain (tunetheweb.com) and the www version (www.tunetheweb.com). It's common to only have one SSL Vhost set up for both domains, perhaps with a redirect to the preferred version, which in Apache config might look like this (note I've stripped down even the necessary settings in this excerpt):

<VirtualHost *:443> ServerName www.tunetheweb.com ServerAlias tunetheweb.com #Set HSTS so repeat visitors come straight to https for two years (63072000) Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains" </VirtualHost>

This vhost entry is used by www.tunetheweb.com, and thanks to the alias is also used for tunetheweb.com. However crucially, as this is the first vhost, it is also the default vhost so it would be used for both sites even without those settings. So, even if we didn't set the ServerAlias, if you go to https://tunetheweb.com then you will pick up the above config even though it doesn't match the ServerName and so you will pick up the HSTS header and, as it has the includeSubDomains flag this means all subdomains must be HTTPS.

Why is this a problem? Well you might run internal servers (e.g. test.tunetheweb.com) or services which are not HTTPS, and they all will now require HTTPS, when you only meant to set this on your external website. This is particularly a problem for business that reuse their website domain a lot internally and for lots of sites which do not use HTTPS. If anyone happens to visit your bare domain (e.g. https://example.com) then suddenly http://intranet.example.com will stop working as it will automatically upgrade to HTTPS even if that is not set up on the server.

Similarly I run a http://report.tunetheweb.com web address to report HPKP errors and it has to be on HTTP as it is used to report any HTTPS errors. Yes there are other ways of handling this (using an alternative domain, or even a tool hosted by someone else) but that's the set up at present, so I have a requirement for some HTTP on this site.

To set this up properly for those of us not fully on HTTPS for all servers under that domains, therefore requires a little extra thought, and setting up three different vhosts:

<VirtualHost *:443> ServerName anythingelse #Do NOT set HSTS header in default so any other ways to this server are not set </VirtualHost> <VirtualHost *:443> ServerName tunetheweb.com #Do NOT set includeSubDomains on HSTS header in top level domain as subdomains (e.g. report.tunetheweb.com) may not all be https Header always set Strict-Transport-Security "max-age=63072000;" </VirtualHost> <VirtualHost *:443> ServerName www.tunetheweb.com #Set HSTS so repeat visitors come straight to https for two years (63072000) Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains" </VirtualHost>
  1. The first one is the default and should not be used (but might be used if you got to another domain that you do not have a HTTPS site set up such as report.tunetheweb.com for this site). Note it has a dummy ServerName that should never be matched, but as it's the first config, Apache uses it as the default (note this does create a warning message in the error log but it can be ignored). This config does not have the HSTS header set at all. Note also that you probably won't ever use this vhost as you'll get a certificate error for anything that visits here (unless you have a wildcard certificate) but better safe that sorry to have it.
  2. The second config is used by the top level domain, so it has the HSTS header set, but without the includeSubDomains flag.
  3. Finally the third config is used by the www.tunetheweb.com server and sets the HSTS header with the includeSubDomains flag.

The above therefore allows you to safely use the HSTS on your website only, though it will require extra set up for any other hosts you set up (e.g. if you set up https://blog.tunetheweb.com in future then might need to add a ServerAlias to the last config to ensure it's set there properly). All the other SSL config should be listed in each as appropriate (e.g. if using the same certificate for each site then set this up in all three configs), so any SNI aware browsers will still work when they load the correct config.

Chrome and Opera allows you to view, delete or set up HSTS policies by typing the following into the address bar: chrome://net-internals/#hsts .

You can also request to include your website in the preload list used by Chrome and other browsers, so that users will automatically use HTTPS even before they visit your website for the first time to load this header. To do this visit the https://hstspreload.appspot.com/ website and submit your site. Note this requires the includeSubDomains flag, which I don't always recommend as discussed above, and also a preload flag I haven't discussed before. How scalable this is remains to be seen. Additionally this removes the control of this flag completely from your server and so is incredibly risky if you set this up incorrectly. A number of sites have already requested to be removed from this preload list but this takes some time to filter down to the next release (3 months minimum for Chrome and no defined timeframe for other browsers).

While you can (and should!) test this before submitting to the preload list it is, in my opinion, far too easy to miss something in your testing. For example to miss visiting your bare domain as discussed above, for all employees in your organisation. Probably the best way around this is by adding a resource to your website from your bare domain (e.g. https://example.com/pixel.png) to force the bare domain HSTS policy to be picked up. This should be done before you submit to the preload list to improve testing coverage as everyone who visits your main site will not have the full policy. This will work even if you redirect the image to the full www domain as HSTS header is loaded on 301/302 redirects. This allows you to see if preloading the bare domain will cause issues and easily rollback this policy while it's still under your control. However not everyone will know to do this extra check.

Support

Web server support is not an issue since this is just another header and every major web server has the ability to add custom headers as response codes. Browser support is strong with all modern browsers supporting this and only older versions of Internet Explorer and Android, and of course the fun that is Opera Mini not supporting this, at the time of writing.

The Downsides

One of the main issues of HSTS is that it is a trust on first use policy. There's nothing to stop the hacker removing that HSTS Header so to avoid this you need to have visited the real website first, so the browser has loaded the HSTS policy into it's settings, and uses that going forward. However the risk is much reduced except for those visiting a website for the first time on a hacked network. Additionally it's possible to preload the website into the browser as discussed above - but that has it's own considerable downsides.

The other downsides are the risk of DoSing yourself if you are not running on HTTPS website, or set this at the top level domain, without fully understanding what that does, as discussed above. As with any setting you should understand it fully before turning it on.

It also ties you in to HTTPS for a long time. No bad thing, most would agree, but there may be reasons to turn it off. For example what if you sell your domain and the new owner doesn't want this? This is particularly relevant with the preload option which is even more set in stone.

I've a longer blog on some of the dangers of HSTS and other security headers.

Summary

HTTP Strict Transport Security (HSTS) is an important setting that all HTTPS-only sites should use. After understanding the risks outlined in this page, and ensuring you set this up correctly there is no maintenance required for this security setting, so it's a one off hit for a long term gain. As well as adding security, the reduction in the redirect improves performance, and finally also can help avoid mixed content alerts for resources accidentally served over HTTP on the same domain. We strongly recommend using, though the use of includeSubdomains and the preload list will take some more thought and may not be possible for all sites.

This page was originally created on and last edited on .

How useful was this page?
Loading interactions…