Understanding HSTS
HTTP Strict Transport Security (HSTS) is a security header that tells browsers to only communicate with your website over HTTPS. Once a browser receives a valid HSTS header from your site, it will automatically convert all subsequent HTTP requests to HTTPS requests before they leave the browser. This eliminates the vulnerability window that exists when a user first types your URL without specifying a protocol or clicks an HTTP link.
HSTS was introduced to counter a specific class of attacks known as SSL stripping, first demonstrated by Moxie Marlinspike in 2009. In an SSL stripping attack, an attacker performing a man-in-the-middle attack intercepts the initial HTTP request from the user and proxies the connection, maintaining an HTTP connection with the victim while establishing an HTTPS connection with the server. The user never sees the HTTPS redirect, and all traffic between the user and the attacker flows over unencrypted HTTP. HSTS prevents this by ensuring the browser never makes an HTTP request in the first place.
How HSTS Works
When a browser connects to a site over HTTPS and receives the Strict-Transport-Security header, it records the domain and the policy duration. From that point forward, any attempt to access the site over HTTP is automatically upgraded to HTTPS by the browser internally, without making any network request over HTTP. The upgrade happens via an internal 307 redirect, meaning the browser never sends an unencrypted request.
The header syntax is:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Important: the HSTS header is only respected when delivered over a valid HTTPS connection. If sent over HTTP, browsers ignore it. This is a security measure to prevent an attacker on an insecure connection from injecting a malicious HSTS policy.
HSTS Directives
max-age
The max-age directive specifies how long, in seconds, the browser should remember to enforce HTTPS for the domain. Common values include:
max-age=300- 5 minutes (for testing)max-age=86400- 1 daymax-age=604800- 1 weekmax-age=31536000- 1 year (recommended for production)max-age=63072000- 2 years (required for preload submission)
Every time the browser visits the site and receives the header, the timer resets. Setting max-age=0 instructs the browser to remove the HSTS policy for the domain, which is how you opt out of HSTS if needed.
includeSubDomains
The includeSubDomains directive extends the HSTS policy to all subdomains of the domain that sets the header. If example.com sets HSTS with includeSubDomains, then mail.example.com, api.example.com, and every other subdomain will also be forced to HTTPS.
This directive is important for security because without it, an attacker could set up a subdomain cookie on an HTTP subdomain and potentially use it to attack the main domain. However, you must ensure that all subdomains support HTTPS before enabling this directive, or users will be unable to access subdomains that only serve HTTP.
preload
The preload directive signals that the domain owner wants their domain included in the HSTS preload list. This directive alone does not add the domain to the preload list; you must also submit your domain at hstspreload.org. The preload directive is a declaration of intent rather than a functional directive.
The HSTS Preload List
The HSTS preload list is a list of domains hardcoded into browsers (Chrome, Firefox, Safari, Edge, and others) that must always be accessed over HTTPS. Unlike regular HSTS, which requires a first visit over HTTPS to set the policy (the "trust on first use" problem), preloaded domains are protected from the very first connection because the browser already knows they require HTTPS.
To be eligible for the preload list, your domain must:
- Serve a valid HTTPS certificate.
- Redirect all HTTP traffic to HTTPS on the same host.
- Serve the HSTS header on the base domain over HTTPS with
max-ageof at least 2 years (63072000 seconds). - Include the
includeSubDomainsdirective. - Include the
preloaddirective.
Submitting to the preload list is a serious commitment. Once a domain is preloaded, removing it is slow and difficult, as it requires a browser update cycle that can take months. Before submitting, ensure that every subdomain supports HTTPS and that you will not need to revert to HTTP for any reason.
Deploying HSTS Safely
HSTS deployment should be gradual to avoid accidentally locking users out of your site. Follow this recommended approach:
- Ensure full HTTPS support: Verify that your site and all its resources (images, scripts, stylesheets, fonts, API endpoints) load correctly over HTTPS. Fix all mixed-content warnings. Confirm that your SSL/TLS certificate is valid, not expired, and covers all necessary domains and subdomains.
- Implement HTTP to HTTPS redirects: Set up 301 redirects from HTTP to HTTPS for all pages. This ensures users who arrive via HTTP are directed to the secure version.
- Start with a short max-age: Deploy HSTS with
max-age=300(5 minutes). This allows you to quickly revert if something goes wrong, since the browser will stop enforcing HSTS after 5 minutes. - Test thoroughly: Access your site from different browsers and devices. Check that all pages, subdomains, and resources work correctly. Use security header testing tools to verify the header is present and correctly formatted.
- Gradually increase max-age: Move to 1 day, then 1 week, then 1 month, and finally 1-2 years. At each step, monitor for issues.
- Add includeSubDomains: Once you have confirmed all subdomains support HTTPS, add the
includeSubDomainsdirective. - Consider preload: If you are confident in your HTTPS setup and want the strongest possible protection, submit to the preload list.
Common HSTS Pitfalls
- Setting a long max-age prematurely: If you deploy HSTS with a 1-year max-age and then discover a problem that requires reverting to HTTP, users who received the header will be unable to access your site over HTTP for up to a year. Their only options are clearing their browser's HSTS cache (which most users do not know how to do) or waiting for the max-age to expire.
- Forgetting about subdomains: Enabling
includeSubDomainswhen some subdomains do not support HTTPS (such as internal tools, staging environments, or legacy systems) will make those subdomains inaccessible. - Certificate expiration: If your SSL certificate expires while HSTS is active, browsers will display a hard error with no option to proceed. Unlike a normal certificate error where users can click through a warning, HSTS makes certificate errors non-bypassable. Set up certificate monitoring and auto-renewal.
- Mixed content: HSTS forces HTTPS connections, but it does not fix mixed-content issues within your pages. Hardcoded HTTP URLs for scripts, images, or other resources will either be blocked or upgraded (depending on the browser), potentially breaking page functionality.
- Load balancers and proxies: If your site sits behind a load balancer or CDN, make sure the HSTS header is not stripped. Also ensure that the backend connection between the load balancer and your origin server is properly configured.
HSTS and Related Security Headers
HSTS is one component of a comprehensive security header strategy. While HSTS handles transport encryption, other headers address different attack vectors. Content Security Policy controls which resources the browser loads, preventing XSS attacks. X-Content-Type-Options prevents MIME-type confusion. X-Frame-Options prevents clickjacking. Deploying all of these headers together provides layered protection that addresses multiple attack vectors simultaneously. See our guide on how to configure security headers for implementation details.
Server Configuration Examples
Adding HSTS to your web server is straightforward:
# Apache (.htaccess or virtual host)
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
# Nginx (server block)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
A WAF or CDN can also inject the HSTS header at the edge, ensuring it is present even if your origin server does not set it.
Summary
HSTS is an essential security mechanism that eliminates an entire class of attacks by ensuring browsers only communicate with your site over encrypted HTTPS connections. Deploy it gradually, starting with a short max-age and increasing over time. Consider preloading for maximum protection, but understand the commitment it requires. Combined with other security headers, HSTS forms a critical part of your site's defense-in-depth strategy.
Need help securing your infrastructure? Explore NOC.org plans to get started.