Although HTTPS provides a huge security increase when compared to the HTTP protocol, there is still room for improvement. First of all, we can use OCSP stapling to validate the SSL certificate on the server instead of the client, improving both security and speed.
Another known HTTPS issue is that it may be vulnerable to man in the middle (MITM) attacks.
What's a Man in the Middle attack?
Imagine that John is having a conversation with Sandra. To communicate, they trust a third party (in this case, a webserver), to properly deliver the messages between them.
Now, if this conversation is not performed using a secure channel, somebody (Man in the Middle) can intercept the messages, and secretly act as the server, being able to even modify the messages.
How to protect your website against Man in the Middle using HSTS
When you write, for example, learn.techseo.blog in your address bar, your web browser will try to load the HTTP page by default. This happens because the browser cannot assume that your website will have an active TLS certificate, so it will try to load the HTTP version and, if configured, redirect to the HTTPS version.
This first connection is unencrypted and, thus, is susceptible to MITM attacks.
HSTS (HTTP Strict Transport Security) tells browsers to only accept secure connections. This is done by using the Strict-Transport-Security
header, which specifies the time period (in seconds) in which browsers must only accept connections over HTTPS.
This would be an example of an HSTS configuration of one year:
Strict-Transport-Security: max-age=31536000
For development and staging environments, it's common to use 6 months as the max-age
meanwhile, for production, the most common configuration is 2 years.
Maximizing HSTS security
HSTS can be configured to be applied in every subdomain:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
If we don't include preload
, the browser will use HSTS for every subsequent connection, but not for the first connection.
Submitting our website to the HSTS listing
To make it even better and faster, web browsers periodically download a list of every HSTS preload domain and subdomain. To submit your website to this list you have to fulfill a few requirements:
- Serve a valid SSL/TLS certificate
- Redirect all traffic from HTTP to HTTPS
- Serve all subdomains over HTTPS
- Serve an HSTS header with a
max-age
of, at least, 1 year (it's recommended to use 2 years). This header must contain theincludeSubdomains
andpreload
directives. - The HTTP to HTTPS redirection must also contain the HSTS header.
You can submit your website by clicking here. To do it, you just have to introduce your domain name in the top-input and accept the conditions 🥳.
⚠️ Special considerations
Please, be aware that enabling HSTS in a misconfigured domain can cause serious problems, as it would not allow users to access the domain anymore. Please, make sure your SSL certificate, redirections, and headers are properly set before continuing.
Configuring HSTS using .htaccess
We just have to include the following header inside our .htaccess:
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Configuring HSTS using NGINX
NGINX also makes it super easy to configure HSTS:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
Configuring HSTS using PHP
Although it's highly recommended to configure it server-side, there will be times in which we do not have control over our server and we have to configure it by code.
This is how we would do it in PHP:
<?php
header("Strict-Transport-Security: max-age=31536000; includeSubDomains; preload");
Configuring HSTS using Laravel
In Laravel, we can use a global middleware to ensure HSTS:
<?php
namespace App\Http\Middleware;
use Closure;
class EnsureHSTS
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
return $next($request)
->header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
}
}
Configuring HSTS using ExpressJS in NodeJS
Inside their documentation, ExpressJS recommends using Helmet to secure your site using HSTS:
First of all, we need to install Helmet:
$ npm install helmet
Then, we add helmet to our express application:
const express = require("express")
const helmet = require("helmet")
const app = express()
app.use(helmet())
Configuring HSTS using Django
As always, Python provides a super-easy solution to enable HSTS 🥳. To enable it, just add the following configuration on your settings.py:
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
Recap
We've seen why using HSTS is essential to avoid MITM attacks, as well as how to configure it and submit it to the Preload list. 🤩