Setting up HSTS in nginx

The HTTP Strict Transport Security (HSTS) header allows a host to enforce the use of HTTPS on the client side. By informing the browser to only use HTTPS, even if the user specifies HTTP as the protocol, the browser will enforce the use of HTTPS. This protects the user from various forms of SSL stripping attacks and provides the host an option to better enforce the use of secure communications. 

What is HSTS?

My previous blog on HSTS goes in to a lot more detail about exactly what HSTS is and how it works. In essence, the host server returns the HSTS header with responses sent over HTTPS. Once the browser picks up on the header, it will store the response and from then on, only communicate with the host using a secure transport layer for the duration of 'max-age' set in the header. I've detailed how to issue the HSTS header in PHP, but that isn't the most ideal way.

Setting up HSTS in nginx

To be fully HSTS compliant a host should only issue a HSTS header over a secure transport layer. This is because an attacker can maliciously strip out or inject a HSTS header into insecure traffic. For that reason, a browser should also disregard any HSTS headers received via HTTP, so technically it shouldn't matter if you do issue it over HTTP. Still, it's best to do it right. In your nginx server block, specifically the one that listens on port 443, you need to add a new response header.

server {
listen 443 ssl;

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";

The 'max-age' values specifies how long, in seconds, you want the client to treat you as a HSTS host.  That is, how long you want them to contact you using HTTPS exclusively. The value I'm using here is 1 year and each time the client visits my site and receives the header, the timer is reset back to a year. Assuming your browser is HSTS compliant, after the first page load over HTTPS, you will no longer be able to communicate with me via HTTP, the browser will prevent it. The 'includeSubDomains' directive is fairly self explanatory. I don't have any sub-domains on my blog but I still issue the directive as a precaution. If you want the HSTS policy to be enforced on all of your sub-domains, include the directive in your header.

HSTS, coupled with server side redirection from HTTP to HTTPS, offers a more robust implementation of SSL as the browser is now aware that you expect secure comms. If a Man In the Middle tries to strip out SSL from your communications by acting as a proxy, your browser will refuse the connection because it is expecting HTTPS and not HTTP.

Author image
About Scott Helme