How to Enable HSTS in Nginx, Apache, Flask, NodeJS

Published on December 09, 2023

HTTP Strict Transport Security (HSTS) is a standard to protect visitors by ensuring that their web browsers are always connected via HTTPS. It is a security mechanism that helps to protect websites from man-in-the-middle attacks (MITM).

How to enable HSTS in Nginx, Apache, Flask and NodeJS

How does man-in-the-middle attack work?

If the browser connects to a website, say a banking website, a hacker can intercept the communication between both parties - the user and the bank website. The hacker can modify the web traffic. A possible scenario is when using a public wifi at a coffee shop or the airport. The hotspot may be a malicious one run by a hacker, who can later monitor the activity and change important information in transit.

In the worst case, the hacker can make money transfers using the banking website after intercepting the web traffic. Now, all this happens when the web traffic is sent via http:// instead of via https://.

A common approach for a web server is to accept both http and https connections. If the user requests a website through http, they get redirected to the https version. This can lead to an MITM attack.

What does an HSTS-enabled website do?

When a user visits an HSTS-enabled website, the browser always uses an https:// connection even when clicked on an http:// URL. It does this by instructing browsers to only connect to the website using HTTPS, and to never backtrack to HTTP.

When the browser encounters the Strict-Transport-Security in the response header, it knows that it can only access the website via https and not http, even if requested by http.

The browser also updates the expiration time for the website from the time (in seconds) sent by the web server.

You can read the standards document from ietf.org.

How do I enable HSTS on a web server?

To enable HSTS, at the very least, the web server returns something like this in the response headers:

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

The above response tells the browser to enable HSTS for that domain or subdomain for 31536000 seconds, which translates to one year.

If you want to make the browser remember for 2 years, the web server is configured to return this in the headers (63072000 seconds is 2 years):

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

If we want to extend the HSTS policy to all the subdomains in that website, so we add includeSubDomains:

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

A third addition is to use the preload parameter so that the browser caches the HSTS policy in its cache.

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

The recommended response is to send something like this:

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

Set the Strict Transport Security header on Nginx

Add this block of code to nginx.conf or conf file for that domain:

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

Restart your Nginx web server.

sudo systemctl restart nginx

Set the Strict Transport Security header on Apache

Add this block of code to your .htaccess or htaccess conf file:

<IfModule mod_headers.c>
Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" env=HTTPS
</IfModule>

Restart your Apache web server.

sudo systemctl restart apache2

Set the Strict Transport Security header in Flask applications

If you have a Python Flask application running and it returns the headers directly use this code. You can add it in an after_request decorator:

@app.after_request
def add_hsts(response):
  response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains; preload'
  return response

This is a fully working Flask program that has enabled HSTS:

app.py

from flask import Flask

app = Flask(__name__)
@app.after_request
def after_request_func(response):
  response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains; preload'
  return response

@app.route("/")
def index():
  print('Hello!')

if __name__ == "__main__":
  app.run()

Set the Strict Transport Security header in NodeJS applications

If you have a NodeJS application running on ExpressJS and it returns the headers directly, you can use Helmet library. This code should work:

app.use(
  helmet.hsts({
    maxAge: 31536000,
    includeSubDomains: true,
    preload: true,
  })
);

How to test if a website is HSTS-enabled

To test if a website (say aruljohn.com) has enabled HSTS, run this on the command line:

curl -sI https://aruljohn.com | grep -i 'strict-transport'

The output will be like this:

$ curl -sI https://aruljohn.com | grep -i 'strict-transport'
strict-transport-security: max-age=31536000; includeSubDomains; preload

If HSTS is not enabled, the grepped response will be blank.

Did this work for you?

If this did not work for you or you have any questions, always feel free to contact me and I will try to reply within 24-48 hours.

Related Posts

If you have any questions, please contact me at arulbOsutkNiqlzziyties@gNqmaizl.bkcom. You can also post questions in our Facebook group. Thank you.

Disclaimer: Our website is supported by our users. We sometimes earn affiliate links when you click through the affiliate links on our website.

Published on December 09, 2023