DEV Community

Sonica Arora
Sonica Arora

Posted on

HSTS Preloading using Nginx, Letsencrypt and Capistrano.😎

Quick tip: HSTS stands for HTTPS Strict Transport Security.

HSTS is a security policy mechanism that protects against protocol downgrade attacks. In simple terms it means forcing the browsers to always use https over http for your website. HSTS also protects against cookie hijacking but we'll leave that discussion out for another post.

In the post below we talk about how to quickly configure your web-server (nginx) to imply HSTS on all subsequent requests and then hardcode this rule into Chrome and other major browsers to default on https for your website using HSTS preloading.

We're doing this on Bubblin Superbooks now. πŸ˜‡

I recommend reading the following blog by Scott Helme to learn more about HSTS preloading.

…a list of hosts that wish to enforce the use of SSL/TLS on their site is built into a browser. This list is compiled by Google and is utilised by Chrome, Firefox and Safari. These sites do not depend on the issuing of the HSTS response header to enforce the policy, instead the browser is already aware that the host requires the use of SSL/TLS before any connection or communication even takes place.

The β€˜preloading’ part here is a way for site administrators to tell the vendors in advance that their site is on https only. This way browsers can skip trying downgraded requests over insecure http altogether.

HSTS directive for Nginx

Now we use the old boy Capistrano for automatic deployments of Bubblin and serve books over https only, so configuring nginx over to strict https with preloads was super easy. I edited the template picked up by the capistrano3-nginx gem for http --> https redirection and added the following directive at the end of the file to what is now our latest nginx config template.


# Path to ./config/deploy/templates/nginx_conf.erb on your rails app
# Jump over to the last line!
… 

server {
    listen 80;
    listen [::]:80 ipv6only=on; 
    server_name <%= fetch(:nginx_server_name) %> www.<%= fetch(:nginx_server_name) %>;
    rewrite ^(.*) https://$host$1$request_uri permanent;
}

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;  
  server_name www.<%= fetch(:nginx_server_name) %>;


  # Redirection from http --> https is mandatory.
  rewrite ^ https://<%= fetch(:nginx_server_name) %>$request_uri permanent; 

}

server {
  server_name <%= fetch(:nginx_server_name) %>;
  root <%= current_path %>/public;
  try_files $uri/index.html $uri @puma_<%= fetch(:nginx_config_name) %>;

  …
  …

  # Plenty of nginx configuration here.

  # SSL is mandatory for HSTS. We're using 
  # Certbot to manage Letsencrypt for us.

  listen 443 ssl http2; # managed by Certbot
  listen [::]:443 ssl http2;



  # Add HSTS header with preload. This is the line that does it.
  add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";

}

The HSTS directive add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"; at the bottom does it and tells the user's browser to always use https for your site.

Commit the changes and then re-deploy ($ cap production deploy). Now head over to hstspreload.org.

This is where we submit our site for inclusion in Chrome's HTTP Strict Transport Security (HSTS) preload list. The list of sites that are hardcoded into Chrome as being https only. Most major browsers like Firefox, Opera, Safari, IE 11 and Edge also have HSTS preload lists based on the list compiled by Chrome. In order to be accepted to and remain on the HSTS preload list through this form, your site must satisfy the following set of requirements perpetually:

1. Serve a valid 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.
4. Serve an HSTS header on the base domain for HTTPS requests:
    i. The max-age must be at least 31536000 seconds (1 year).
    ii. The includeSubDomains directive must be specified.
    iii. The preload directive must be specified.
    iv. 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).

It should also be noted here that hardcoding HSTS preloading into browsers doesn't automatically mean that all aspects of security have been taken care of. It surely helps with security and plus there is a small improvement in speed and performance of your web-server because it no longer has to determine and switch between secure and insecure protocols.

That's all there is to it with HSTS folks. ❀️


I'm Sonica Arora, CTO of Bubblin Superbooks and you can follow me here on Twitter.

P.S.: Did you know that Bubblin is a cool new way to read books on your iPad?

Top comments (2)

Collapse
 
drussilla profile image
Ivan Derevianko

Thanks for this article! Unfortunately, 95% of the websites do not have property configured HSTS at all :(

Collapse
 
dineshrathee12 profile image
Dinesh Rathee

LetsEncrypt have revoked around 3 million certs last night due to a bug that they found. Are you impacted by this, Check out ?

DevTo
[+] dev.to/dineshrathee12/letsencrypt-...

GitHub
[+] github.com/dineshrathee12/Let-s-En...

LetsEncryptCommunity
[+] community.letsencrypt.org/t/letsen...