Understanding HSTS: Enforcing HTTPS
HTTP Strict Transport Security (HSTS) is a security policy mechanism that forces web browsers to always use HTTPS (encrypted connections) when communicating with your website. Without HSTS, a user's first visit or a user visiting a bookmarked HTTP URL will start unencrypted, opening a window for attackers. HSTS closes this window by instructing browsers to never use HTTP for your domain.
The Problem HSTS Solves
Consider a user visiting your website:
Without HSTS:
- User types "example.com" in the browser
- Browser initiates HTTP request to example.com (unencrypted)
- Server responds with a redirect to HTTPS
- Browser follows redirect to HTTPS
- Connection is now encrypted
The vulnerability window: Between steps 1-3, an attacker with network access (corporate network, coffee shop WiFi, ISP, etc.) can:
- Intercept the HTTP request
- Respond with their own content or redirect
- Steal credentials, inject malware, or redirect to phishing sites
Even though the eventual connection is HTTPS, the initial HTTP request is unencrypted and vulnerable.
With HSTS:
- Browser has previous history of visiting example.com with HSTS enabled
- Browser automatically upgrades example.com to HTTPS before making any request
- No HTTP request is ever made
- The vulnerability window is eliminated
How HSTS Works
HSTS is communicated through an HTTP header:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Breaking this down:
max-age=31536000 - The duration (in seconds) that the browser should enforce HTTPS. 31536000 seconds is one year. This tells the browser: "For the next year, always use HTTPS for this domain."
includeSubDomains - Applies HSTS to all subdomains. Without this, only the exact domain (example.com) requires HTTPS; subdomains like api.example.com could use HTTP.
preload - Opts your domain into the HSTS preload list (explained below).
The HSTS Preload List
The HSTS preload list is a hardcoded list of domains that should always use HTTPS, built into every modern browser. When Google Chrome, Firefox, Safari, and Edge are built, they include a list of approximately 20,000 domains that require HTTPS.
This solves the bootstrapping problem: the first time a user visits your website, there's no HSTS header to enforce HTTPS. With preloading, your domain is already in the browser's list, eliminating the first-visit vulnerability.
To get your domain on the preload list:
- Implement HSTS with all three parameters (max-age, includeSubDomains, preload)
- Ensure all subdomains work over HTTPS
- Submit your domain to https://hstspreload.org/
- The submission is reviewed and added in the next browser release
Once preloaded, every browser automatically enforces HTTPS for your domain even on first visit.
HSTS Effectiveness Against Attacks
Man-in-the-Middle (MITM) Attack Prevention:
- Attacker cannot intercept and redirect HTTP traffic
- Attacker cannot serve phishing pages over HTTP
- Attacker cannot steal unencrypted credentials
SSL Stripping Attack Prevention:
- Attackers often downgrade HTTPS to HTTP to intercept traffic
- HSTS prevents downgrade because browser won't use HTTP
- Even if attacker intercepts, browser won't connect via HTTP
Cookie Theft Prevention:
- Cookies sent over HTTP are vulnerable
- With HSTS enforcing HTTPS, cookies are only sent over encrypted connections
- Session tokens and authentication cookies are protected
HSTS Side Effects and Considerations
Subdomain Inclusion:
Strict-Transport-Security: max-age=31536000; includeSubDomains
This applies HSTS to ALL subdomains. Every subdomain (api.example.com, cdn.example.com, mail.example.com, etc.) must support HTTPS. If you forget to secure even one subdomain, it becomes inaccessible once HSTS is cached.
Permanent Application: Once set, HSTS persists in the browser's cache for the specified duration (typically one year). If you remove HSTS or your HTTPS certificate fails, the domain remains inaccessible via HTTP until the cache expires.
Preload List Permanence: Removing your domain from the preload list takes a long time (multiple browser release cycles, 1-2 years). Plan HSTS carefully if you might need to disable it later.
Implementation Best Practices
Gradual Rollout:
# Week 1: Short duration to test
Strict-Transport-Security: max-age=3600
# Week 2: Increase duration
Strict-Transport-Security: max-age=86400
# Week 3: Add includeSubDomains
Strict-Transport-Security: max-age=31536000; includeSubDomains
# After 1 year: Submit for preload
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Start with short max-age values while ensuring all your infrastructure supports HTTPS. Gradually increase as you gain confidence.
Before Implementing HSTS, Ensure:
- All pages serve over HTTPS
- All resources (CSS, JS, images) load over HTTPS
- All subdomains support HTTPS
- Redirects from HTTP to HTTPS work correctly
- You never need to revert to HTTP for this domain
Testing with Browser Dev Tools: Most browsers allow you to inspect HSTS status in developer tools, helping verify implementation.
HSTS in Different Contexts
APIs and Microservices:
Strict-Transport-Security: max-age=31536000
APIs should use HSTS without preload (unless the API domain is public-facing and suitable for preload).
Mobile Apps: Most mobile apps make HTTP requests directly, ignoring HTTP-level headers. HSTS helps only with web-based APIs or web views.
Third-Party Content: HSTS applies to the domain that sends the header. Third-party resources (ads, analytics) aren't affected unless those third parties also implement HSTS.
Relationship to Other Security Headers
HSTS and Content-Security-Policy: CSP can be used to enforce HTTPS:
Content-Security-Policy: upgrade-insecure-requests
This upgrades insecure requests to HTTPS. HSTS is stronger—it prevents HTTP entirely.
HSTS and HTTPS Redirects:
# Without HSTS: HTTP → HTTPS redirect
# With HSTS: Skip HTTP entirely
HSTS makes explicit HTTP redirects unnecessary and prevents the vulnerability window they create.
Checking HSTS Implementation
SSL Checker examines HSTS configuration:
- Check "Security Headers" section
- Look for "Strict-Transport-Security" header
- Verify max-age is appropriate (31536000 for production)
- Check if includeSubDomains is present
- Check if preload is present (only if applicable)
A properly implemented HSTS header should show:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Common Mistakes
Setting HSTS on HTTP URL:
# Wrong: Sent over unencrypted HTTP
http://example.com returns HSTS header
HSTS is only transmitted over HTTPS. Setting it on HTTP responses is ineffective for first-time visitors.
Not Including SubDomains Without Planning:
If you include includeSubDomains without ensuring all subdomains support HTTPS, you'll break those subdomains.
Too-Short max-age:
Strict-Transport-Security: max-age=300 # 5 minutes
Too short and the header expires quickly, reducing effectiveness. Use 31536000 (one year) or longer.
Forgetting Wildcard Subdomains: If you use wildcard DNS (*.example.com), ensure all potential subdomains can support HTTPS.
Real-World Attack Scenario
Without HSTS:
- Corporate network intercepts HTTP request to example.com
- Attacker redirects to https://attacker-example.com (certificate warning shown)
- User ignores warning (common behavior)
- Attacker captures credentials
With HSTS:
- Browser has example.com in HSTS cache
- Browser automatically uses HTTPS
- Attacker cannot intercept HTTP (no HTTP request made)
- Attacker cannot present fake certificate (browser expects real example.com certificate)
- Attack fails
HSTS and Public Suffixes
Domains on public suffix lists (like .github.io, heroku.com) often have HSTS with includeSubDomains to protect all user-controlled subdomains.
If you're on a shared platform, pay attention to HSTS headers set by the platform—they may restrict your ability to use HTTP.
Performance Impact
HSTS has minimal performance impact:
- No additional network requests
- Small header size (~70 bytes)
- Browser stores HSTS in local cache (negligible storage)
The only performance consideration is that any user visiting HTTP is redirected to HTTPS, adding one extra redirect. This is actually desirable (the extra security is worth one additional hop).
Recommendations
- Implement HSTS - Essential security control for all HTTPS sites
- Use max-age=31536000; includeSubDomains - Standard production configuration
- Test thoroughly - Ensure all subdomains support HTTPS before implementing
- Plan for permanence - Don't implement HSTS unless you're committed to HTTPS long-term
- Submit for preload - After running HSTS successfully for months
- Monitor with SSL Checker - Regularly verify HSTS is properly configured
- Document policy - Note why HSTS is configured and what it protects
Conclusion: HSTS Is Essential for Modern HTTPS
HSTS is one of the most important security headers you can implement. It eliminates the first-visit and SSL-stripping vulnerabilities that plague even properly-implemented HTTPS sites. Combined with valid certificates, proper cipher configuration, and other security headers, HSTS creates comprehensive protection against man-in-the-middle attacks. Every website with HTTPS should implement HSTS—it's simple, effective, and has become a baseline expectation of modern web security.