What it is
HSTS (HTTP Strict Transport Security) is a response header that tells browsers to only connect to your site over HTTPS for a set period. Once set, the browser will refuse to connect via HTTP, which prevents downgrade attacks and cookie hijacking on the first visit.
Why it matters
Without HSTS, the first request to your site (or after the header expires) can be intercepted and downgraded to HTTP by an attacker. HSTS ensures that after the first secure visit, all subsequent requests use HTTPS only.
How it is exploited
On the first request to your site the user types example.com, so the browser opens HTTP first. An attacker on the same Wi-Fi sees the request, replies with a fake HTTP page, and harvests credentials or strips the redirect to HTTPS (sslstrip). HSTS skips that HTTP hop for return visits.
How to fix it
- Choose max-age. Set max-age to at least 31536000 (1 year). Include includeSubDomains if all subdomains use HTTPS. Add preload if you want to submit your site to the browser HSTS preload list.
- Add the header on your server. Send the Strict-Transport-Security response header on every HTTPS response. Use your web server config (Nginx, Apache) or application middleware (Node, Next.js).
- Ensure HTTP redirects to HTTPS first. Before enabling HSTS, make sure all HTTP traffic redirects to HTTPS (301). Otherwise users may never receive the HSTS header.
- Verify. Run a scan or use your browser dev tools (Network tab) to confirm the Strict-Transport-Security header is present on your HTTPS responses.
Examples by platform
Nginx
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;Apache
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"Node.js (Express)
app.set('trust proxy', 1);
app.use((req, res, next) => {
if (req.secure) {
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
}
next();
});Next.js (next.config.js)
// In next.config.js headers:
headers: [
{ key: "Strict-Transport-Security", value: "max-age=31536000; includeSubDomains; preload" }
]How to verify the fix
Confirm the Strict-Transport-Security header is present in HTTPS responses:
curl -sI https://example.com | grep -i strict-transport-security