HTTP Strict Transport Security
| ID |
|---|
| WSTG-CONF-07 |
Summary
The HTTP Strict Transport Security (HSTS) feature enables a web server to inform the user’s browser, via a special response header, that it should never establish an unencrypted HTTP connection to the specified domain servers. Instead, it should automatically establish all connection requests to access the site through HTTPS. This also prevents users from overriding certificate errors.
Its absence, or a weak configuration, can lead to security issues such as:
- Attackers intercepting and accessing information transferred over an unencrypted network channel.
- Attackers carrying out manipulator-in-the-middle (MITM) attacks by taking advantage of users who accept untrusted certificates, or by downgrading/stripping a redirect to HTTPS (SSL stripping).
- Users who mistakenly enter an address in the browser using HTTP instead of HTTPS, or users who click on a link in a web application that incorrectly uses the HTTP protocol.
Test Objectives
- Review the HSTS header, its directives, and their values for consistency with current best practice.
- Confirm the site is protected against the first-request trust gap, either via preload or an otherwise hardened HTTP-to-HTTPS path.
- Confirm HSTS is applied consistently across the domain and relevant subdomains, and does not mask mixed-content issues.
How to Test
- Confirm the presence of the HSTS header on the HTTPS response by examining the server’s response through an intercepting proxy.
- Use curl as follows:
$ curl -s -D- https://owasp.org | grep -i strict-transport-security:
Strict-Transport-Security: max-age=31536000
- Evaluate the directive values, an example preload-eligible header being
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload:max-age(seconds until the browser stops forcing HTTPS for this host) should be at least31536000(1 year), or63072000(2 years) if the domain is being submitted to, or already on, the HSTS preload list; flag anything materially shorter ormax-age=0outside of an intentional HSTS-disable rollback.- Check whether
includeSubDomains(extends the policy to all subdomains) is present and, if so, spot-check a sample of subdomains - including ones outside the immediate application (mail, internal tools, staging, etc.) - to confirm they all serve valid HTTPS. A subdomain that cannot serve HTTPS will become unreachable to browsers that have cached the policy. - Check whether
preloadis present, and if so, confirm the domain actually appears on the Chromium HSTS preload list that Chrome, Firefox, Safari, and Edge all consume (thepreloaddirective itself has no browser effect; only actual list membership matters):
curl -s "https://hstspreload.org/api/v2/status?domain=example.com"
If preload is present but the domain is not yet listed (or was removed), confirm this is an in-progress submission rather than a stale/no-op directive.
- Check the first-request/redirect path: HSTS only protects requests made after the browser has already seen the header once for that host (Trust On First Use), so a user’s very first visit - or any visit after the cached policy has expired - is still made over plain HTTP unless the host is preloaded, and that first request/redirect can be intercepted or stripped before the browser ever learns about HSTS. Test it directly:
curl -s -D- http://example.com | head -n 5
Confirm this returns a redirect (301/308) to the HTTPS equivalent, and that the resulting HTTPS response carries the HSTS header (the header itself is ignored by browsers if sent over plain HTTP, per spec, so it must be re-asserted on the HTTPS side of the redirect). preload is the only mechanism that closes this gap entirely, since the policy is then shipped inside the browser rather than learned from a prior response.
-
Check the interaction with mixed content: HSTS force-upgrades top-level navigation and same-host subresource requests to HTTPS, but does not rewrite explicit cross-origin
http://references in markup. Inspect the page source/network tab for absolutehttp://otherhost/...references - these are still subject to ordinary browser mixed-content blocking independent of HSTS (see Cross Origin Resource Sharing). Separately, confirm any same-hosthttp://links in markup are HTTPS by design rather than only “working” because HSTS silently upgraded them - that upgrade can mask a link that should have been fixed. -
For applications behind a CDN/load balancer/reverse proxy, confirm the header is added at (or survives through to) the edge that terminates TLS for end users, not only at an internal origin.
Preload List Submission
Submission to the HSTS preload list (hstspreload.org) is a manual, out-of-band step, not something enabled by the header alone. Before recommending submission, confirm the prerequisites are actually met:
- Serve a valid HTTPS certificate on the base domain, and redirect any HTTP request on that domain to HTTPS.
- Serve HTTPS, with a valid certificate, on the
wwwsubdomain if a DNS record for it exists. - Send the
Strict-Transport-Securityheader on the base domain’s HTTPS response withmax-ageof at least31536000(one year, though the site recommends63072000), and bothincludeSubDomainsandpreloadpresent. - Confirm every subdomain, including ones outside the immediate application (mail, internal tools, staging, etc.), can serve HTTPS, since
includeSubDomainsapplies preload-forced HTTPS to all of them.
Because preload-list changes ship inside browser releases and are difficult/slow to reverse (removal can take months to propagate to users on older cached browser builds), submission should be treated as a one-way, organization-level decision - confirm this is authorized before submitting, and do not submit a target’s domain during an assessment.
Remediation
- Send
Strict-Transport-Securityon every HTTPS response, withmax-ageof at least one year. - Redirect all HTTP traffic to HTTPS, and ensure the redirect target itself returns the HSTS header.
- Use
includeSubDomainsonce all subdomains are confirmed to support HTTPS. - Consider
preloadand submission to the HSTS preload list for domains that need protection from the very first connection, after confirming the prerequisites above and getting organizational sign-off given the difficulty of reversing it. - Do not rely on mixed-content upgrading behavior in place of fixing hardcoded
http://links in markup.
Tools
- hstspreload.org - preload list status lookup and submission
- SSL Labs Server Test - reports HSTS configuration alongside TLS configuration
- ZAP - passive scan rule flags missing/weak HSTS
References
- OWASP HTTP Strict Transport Security Cheat Sheet
- OWASP Appsec Tutorial Series - Episode 4: Strict Transport Security
- RFC 6797 - HTTP Strict Transport Security (HSTS)
- hstspreload.org - Preload List Submission Requirements
- Chromium HSTS Preload List Source
- MDN: Strict-Transport-Security
- Enable HTTP Strict Transport Security In Nginx