Part 1 of the series "EU Web Security: 10 Steps to a Better Rating"
The Problem in 30 Seconds
Your website has a TLS certificate. Good. But when a user types http://your-domain.com — what happens?
Without HSTS: The browser connects unencrypted. The site redirects to HTTPS. But in the milliseconds between the HTTP request and the redirect, an attacker on the same network (coffee shop Wi-Fi, airport, hotel) can hijack the connection. Man-in-the-middle, cookie theft, session hijacking — all trivial.
With HSTS: The browser already knows this domain only accepts HTTPS. It connects encrypted directly. No HTTP request, no redirect, no attack window.
One header. One line. And 72.4% of European websites do not have it.
What the Data Shows
From the SiteGuardian Benchmark covering over 700,000 European websites:
- 27.6% have HSTS enabled
- 75.7% redirect to HTTPS — but without HSTS, the redirect is attackable
- 24.3% do not even redirect, despite having a valid certificate
That means: three out of four websites with a TLS certificate do not use it consistently. The certificate is there, the protection is not.
What Exactly Is HSTS?
HTTP Strict Transport Security (RFC 6797) is an HTTP response header that tells the browser:
"Connect to this domain for the next X seconds exclusively over HTTPS. Ignore HTTP completely."
The header looks like this:
Strict-Transport-Security: max-age=31536000; includeSubDomains
max-age=31536000— 1 year (in seconds). The browser remembers the instruction for this long.includeSubDomains— applies to all subdomains (api.your-domain.com, mail.your-domain.com, etc.)
After the first visit, the browser connects directly over HTTPS on every subsequent request — without the detour through HTTP.
How to Enable HSTS
Apache (.htaccess or vhost.conf)
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Prerequisite: mod_headers must be enabled.
Nginx
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
The always at the end ensures the header is sent even on error pages (4xx, 5xx).
Caddy
Caddy sets HSTS automatically when HTTPS is active. Nothing to do.
Node.js / Express
app.use((req, res, next) => {
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
next();
});
Or with the helmet package:
const helmet = require('helmet');
app.use(helmet.hsts({ maxAge: 31536000, includeSubDomains: true }));
WordPress
The "Really Simple SSL" or "HTTP Headers" plugin enables HSTS with a single click. Alternatively, add it to .htaccess (see Apache above).
Managed Hosting (Cloudflare, AWS, Platform.sh, etc.)
Most hosting providers do not set HSTS by default. Check your dashboard under "SSL/TLS settings" or "HTTP headers". If the option is not available, create an .htaccess file in the webroot.
Three Mistakes to Avoid
1. Setting max-age too short
max-age=86400 (1 day) only protects users who visited within the last 24 hours. Start with 30 days (2592000), then escalate to 1 year (31536000) once everything works.
2. Forgetting includeSubDomains
Without includeSubDomains, your subdomains remain reachable over HTTP. If mail.your-domain.com or intranet.your-domain.com do not have TLS, only add includeSubDomains once all subdomains support HTTPS — otherwise they will break.
3. Enabling HSTS without a working HTTPS redirect
HSTS requires that your website is actually reachable over HTTPS. Test before enabling: navigate to https://your-domain.com. If you see an error, fix the TLS certificate configuration first.
HSTS Preload: The Next Step
Once HSTS is running and you are confident all subdomains support HTTPS, apply for inclusion in the HSTS preload list:
- Set the header to:
max-age=31536000; includeSubDomains; preload - Submit your domain at: hstspreload.org
The preload list is built into Chrome, Firefox, Safari, and Edge. Domains on the list are always loaded over HTTPS — even on the very first visit, before the browser has ever seen the HSTS header.
How NIS2 and GDPR Relate
HSTS is not mentioned by name in any law. But:
-
NIS2 Art. 21(2)(d) requires "security in network and information systems acquisition, development and maintenance, including vulnerability handling and disclosure". A missing HSTS header is a known, trivially exploitable vulnerability.
-
GDPR Art. 32 requires "appropriate technical measures" to protect personal data. Transport encryption without HSTS is like a lock without a deadbolt — it looks secure, but can be opened with a single move.
Check Your Domain
Enable HSTS, wait 5 minutes, and scan your domain:
The scan will immediately show you whether HSTS is correctly set, whether includeSubDomains is active, and whether your domain qualifies for the preload list.
Next week in Part 2: DMARC — from none to reject. Why policy=none protects no one, and how to reach an effective DMARC policy in three steps.
This article is part of the series "EU Web Security: 10 Steps to a Better Rating". Data from the SiteGuardian EU Web Security Benchmark covering over 700,000 European websites.