HTTP Strict Transport Security (HSTS) is one of the most impactful security headers you can add to your website. It is a simple, one-line change that eliminates an entire class of man-in-the-middle attacks. If your site supports HTTPS (it should), you need HSTS.
The Problem HSTS Solves
When a user types yoursite.com into their browser address bar, the browser's first request is typically plain HTTP (http://yoursite.com). Your server responds with a 301 redirect to https://yoursite.com. This redirect pattern — "HTTP Strict Redirect" — is how most sites enforce HTTPS.
The problem: that first HTTP request is vulnerable. On a public Wi-Fi network, an attacker performing a man-in-the-middle attack can intercept that initial HTTP request before the redirect occurs, serve a fake HTTP version of your site, and capture login credentials. This attack is called an SSL stripping attack, and it has been reliably exploitable since Moxie Marlinspike's 2009 Black Hat presentation.
How HSTS Works
HSTS tells the browser: "For this domain, always use HTTPS — never attempt plain HTTP." Once the browser has seen the HSTS header, it will not even attempt an HTTP connection for the domain. It upgrades HTTP requests to HTTPS internally, before any network request is made.
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
After receiving this header, the browser remembers the policy for max-age seconds (31536000 = 1 year). Every subsequent visit — for the next year — will automatically use HTTPS.
The Three Directives
max-age
How long the browser should remember and enforce the HTTPS-only policy, in seconds. Recommended minimums:
- 5 minutes (
300) — start here for testing - 1 month (
2592000) — initial production rollout - 1 year (
31536000) — recommended for established sites - 2 years (
63072000) — required for HSTS preload submission
includeSubDomains
Extends the policy to all subdomains. If you set HSTS on yoursite.com with includeSubDomains, then api.yoursite.com, mail.yoursite.com, and all other subdomains are also covered. Only add this if all your subdomains support HTTPS.
preload
Indicates that you want your domain to be included in the HSTS preload list — a list of domains that is hardcoded into browsers (Chrome, Firefox, Safari, Edge). Users who have never visited your site before get HSTS protection on the very first request. The preload directive alone does not add you to the list — you must also submit your domain at hstspreload.org.
How to Add HSTS
Nginx:
server {
listen 443 ssl;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
...
}
Apache:
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Flask:
@app.after_request
def add_hsts(response):
if request.is_secure:
response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains; preload'
return response
Cloudflare: Enable HSTS in SSL/TLS → Edge Certificates → HTTP Strict Transport Security. No code changes needed.
Before You Enable HSTS
HSTS is intentionally hard to reverse. If you enable it with a 1-year max-age and then need to serve HTTP (for example, if your SSL certificate expires and you cannot renew it in time), users who have visited your site will be unable to access it for up to a year. Follow these steps before enabling:
- Ensure all subdomains support HTTPS (if using includeSubDomains)
- Ensure your SSL certificate has plenty of time before expiry
- Start with a short max-age (300 seconds) to test
- Gradually increase to 1 year over several weeks
- Submit to the preload list only after you are confident in your HTTPS setup
HSTS and the HSTS Preload List
The preload list is maintained by Google and baked into Chrome's source code (and adopted by other browsers from the same list). Inclusion provides the strongest possible protection: zero HTTP requests, ever, from any browser. But it is a one-way door — removal from the preload list requires weeks of lead time and browsers update on their own schedule. Domains that get removed from the preload list can experience a gap in coverage during the transition period.
Submit your domain at hstspreload.org — the tool will verify your configuration meets requirements (max-age ≥ 31536000, includeSubDomains, preload) before accepting the submission.
Verifying HSTS Is Working
curl -sI https://yoursite.com | grep -i strict
# Should show: strict-transport-security: max-age=31536000; includeSubDomains; preload
In Chrome DevTools → Application → Storage → View site data — you can see whether HSTS is remembered for the current domain under "HSTS".