For developers, security measures and policy enforcement are a regular routine for our projects. Having a sound security layer and ensuring basic protocols have become the bread and butter for all client-facing platforms. We can't say that 100% of the web is secured adequately from the myriad of threats out there. But we can confidently say that most efforts are pushing the needle in that direction.
That being said, not all security features have the same impact or protect the users in the same way. One such feature is HTTP Strict Transport Security or HSTS.
This article will briefly define what HTTP Strict Transport Security is. We will also see what makes it a fundamental part of secure communication between your server and the client. Additionally, we will explore how to enable HSTS on Node.js properly. Finally, we will examine some of the issues that might arise and how to go about fixing them.
If your level of experience with Node.js is low or you have not dipped your toes in it yet, we recommend you make yourself acquainted with this wealth of information on Node.js. It's essential to have a basic understanding of Node.js to grasp the concepts we will explore in this post.
What Is HTTP Strict Transport Security?
While the web currently relies on SSL/TLS protocols to encrypt and secure the communication between client and server, ensuring that all transactions performed by the browser are in these secure protocols is another matter entirely.
A standard flow for communication with a website is to first make an HTTP request to the domain and, if the server is implementing SSL/TLS with a valid certificate and enforcing HTTPS rerouting, be redirected (301) to the same site with an HTTPS request. This method ensures that all communication between the client and server is performed securely through HTTPS. All good, right?
Well, not really.
MITM Scenario
If we consider a scenario where our unsuspecting user reaches our server through a compromised network—think of a fake access point disguised as legitimate in a public area—the initial handshake can open the door to trouble. By intercepting the communication between the parties, attackers can act as a filter of sorts. They can rewrite all communication between the client to HTTP while keeping the server's transactions encrypted. With this approach, the attackers fool the server into believing that the handshake was successful and all transactions are secure. Meanwhile, the attackers intersect all data the client sends to our server and reads it as it is unencrypted.
This approach is called "man in the middle" or MITM. Additionally, the attack is known as SSL stripping because it basically strips the client from the much-needed security of SSL.
Yikes! So what can we do then?
Well, we can make sure that the browser exclusively communicates with our server using secure protocols and encryption by explicitly telling it to do so. That is, in essence, what HTTP Strict Transport Security does, and it is fundamental to secure our platforms reliably.
How to Enable HSTS on Node.js
Enabling HSTS is quite simple and straightforward. The browser and the security measures already baked in it do most of the work. All you have to do to implement a fundamental layer of security with HSTS is add the following header to your responses:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
A basic implementation of this in Node.js would look like this:
app.use(function(req, res, next) {
if (req.secure) {
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
}
next();
})
This header contains one compulsory and two optional directives.
max-age (compulsory): This directive indicates how long the browser will store the header and effectively comply with the policy. Notice that we have set the value as 31536000, which equates to one year. You can put any value you consider appropriate, but remember that your clients will not have access to your site if there is an issue with your SSL certificate once the browser receives the HSTS policy.
includeSubDomains (optional): This directive indicates whether the subdomains will need to comply with the policy. If you have mywebsite.com with an SSL certificate and set the header for clients who visit it, then www.mywebsite.com and subdomain.mywebsite.com will also be required to follow the same HSTS policy.
preload (optional): This directive indicates that you want to add your site to the HSTS preload list included in the browser. This list essentially cements your website to follow HSTS for that client permanently.
Now that we understand what the HSTS policy is telling the browser to do, let's see what is actually happening.
An error in a Google Chrome browser that says the user's connection is not private.
We can see an error displayed in Chrome, indicating that this website typically works with encryption. Still, the browser detected some shenanigans, so it's stopping you from interacting with the suspicious website.
Correcting HSTS Errors
As stated in the error, the suspicious activity could be an attacker trying to impersonate the server, a WiFi login screen, or maybe the server itself does not have proper SSL/TLS configuration.
Since we know that we set up our website to fail this verification intentionally, our course of action should be to ensure that the setup is correct and, in case we are in the process of deploying HSTS for the first time, to have a proper plan and follow it closely.
Here is a checklist of steps you can follow, inspired by Scott Helme's HSTS tutorial:
Find all subdomains that belong to your site (consult DNS CNAME entries). Note that they might belong to third-party services.
Confirm that the root domain and its subdomains are accessible via HTTPS.
Make sure you configured proper redirection of HTTP to HTTPS.
Set a short expiration time. For example, "max-age=300" (five minutes).
Append the "includeSubDomains" directive if necessary.
Increment "max-age" in stages. Strive for two years of validity.
Once all is good, add the "preload" directive.
Submit your domain to Google's HSTS preload list, which will ensure that future versions of all major browsers have your domain preloaded and marked as secure-only. (This is optional.)
Once you have completed the procedure, your site will be enforcing HTTPS communication only, and new visitors will follow through with the policy.
Of course, no solution is perfect, and there is still some possibility of a breach by highly sophisticated attacks. Nevertheless, implementing SSL/TLS and HSTS policy goes a long way to protect 99.9% of the web.
Summing Up
The HTTP Strict Transport Security policy is, at this point, a fundamental building block for the web. Its implementation is essential to ensure the security of clients who nowadays access our platforms from many different avenues and in a myriad of ways. However, it can be our Achilles' heel if not implemented properly.
The infrastructure of the web itself, as it was built, did not conceive of the possibility of access point impersonation and MITM attacks. This is why we must keep making improvements to the security pipelines that are in use on the web we know and love. And that usually means that we have to work extra hard and stay vigilant of new threats and forms of attack.
This post was written by Juan Reyes. Juan is an engineer by profession and a dreamer by heart who crossed the seas to reach Japan following the promise of opportunity and challenge. While trying to find himself and build a meaningful life in the east, Juan borrows wisdom from his experiences as an entrepreneur, artist, hustler, father figure, husband, and friend to start writing about passion, meaning, self-development, leadership, relationships, and mental health. His many years of struggle and self-discovery have inspired him and drive to embark on a journey for wisdom.