-
Notifications
You must be signed in to change notification settings - Fork 22.8k
Add precision in HSTS page #39853
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add precision in HSTS page #39853
Conversation
* Make the documentation reflect the terminology and details of the RFC more accurately. * Instead of "site" or "website", clarify HSTS policy as applying to domain name without port, and not IP addresses; using terminology of "Known HSTS Hosts" and host's domain name * Explain more clearly the request response cycle and how HSTS applies to subsequent requests * Illustrate relationship between HTTP-to-HTTPS redirects and HSTS; both should be used in tandem
files/en-us/web/http/reference/headers/strict-transport-security/index.md
Show resolved
Hide resolved
files/en-us/web/http/reference/headers/strict-transport-security/index.md
Outdated
Show resolved
Hide resolved
files/en-us/web/http/reference/headers/strict-transport-security/index.md
Outdated
Show resolved
Hide resolved
Your browser remembers `example.com` as a Known HSTS Host, and that it specified `includeSubDomains`. | ||
7. A few weeks later, you are at the airport and decide to use the free Wi-Fi. But unknowingly, you connect to a rogue access point running on an attacker's laptop. | ||
8. You open your browser to `http://login.example.com/`. Because your browser remembers `example.com` as a Known HSTS Host and the `includeSubDomains` directive was used, your browser uses HTTPS. | ||
9. The attacker intercepts the request with a fake HTTPS server, but does not have a valid certificate for the domain. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[markdownlint] reported by reviewdog 🐶
MD029/ol-prefix Ordered list item prefix [Expected: 6; Actual: 7; Style: 1/2/3]
files/en-us/web/http/reference/headers/strict-transport-security/index.md
Outdated
Show resolved
Hide resolved
files/en-us/web/http/reference/headers/strict-transport-security/index.md
Show resolved
Hide resolved
files/en-us/web/http/reference/headers/strict-transport-security/index.md
Show resolved
Hide resolved
@@ -8,10 +8,11 @@ browser-compat: http.headers.Strict-Transport-Security | |||
|
|||
{{HTTPSidebar}} | |||
|
|||
The HTTP **`Strict-Transport-Security`** {{Glossary("response header")}} (often abbreviated as {{Glossary("HSTS")}}) informs browsers that the site should only be accessed using HTTPS, and that any future attempts to access it using HTTP should automatically be upgraded to HTTPS. | |||
The HTTP **`Strict-Transport-Security`** {{Glossary("response header")}} (often abbreviated as {{Glossary("HSTS")}}) informs browsers that the host should only be accessed using HTTPS, and that any future attempts to access it using HTTP should automatically be upgraded to HTTPS. | |||
Additionally, on future connections to the host, the browser will not offer the user a means to bypass secure connection errors, such as an invalid certificate. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean if that you have connected once, and an attacker tries to insert itself somehow and offer an invalid certificate you can't click through "trust this"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. For a Known HSTS Host, conformant browsers do not allow the user to bypass TLS errors. In Chrome for example, without HSTS, you can click "Advanced" and then "Proceed to {domain} (unsafe)". With HSTS, instead Chrome shows this message:
You cannot visit {domain} right now because the website uses HSTS. Network errors and attacks are usually temporary, so this page will probably work later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if we're going to be precise about terms here, like using "host" instead of "site" (and I think we should) then we have to give people a way to understand what these terms mean. Suggestion would be to link to the glossary entry for Host, but unfortunately that isn't very precise. Perhaps we could improve on that entry?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might also say "the host (and optionally its subdomains)" here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was unsure how far to distinguish between "host" and "domain name". As far as I understand, a "host" in general can be an IP address or domain name, but HSTS does not allow IP addresses to be a Known HSTS Host, so for HSTS purposes domain name is what matters. Domain name is clearer to me than host.
However, I was trying to imitate RFC 6797 in distinguishing between host as the active participant (server) and domain name as an identifier for the host. For example, the RFC authors' usage is:
When establishing an HTTP connection to a given host, however
instigated, the UA examines its cache of Known HSTS Hosts to see if
there are any with domain names that are superdomains of the given
host's domain name.
They speak of the "host's domain name" in the possessive has-a sense, and refer to "connecting to" the host, not the domain name.
I tried to honor that usage but it may be overly pedantic; in the end the only thing HSTS cares about is the domain name. I tried to make that clear in the Description section.
Probably the most precise (but overly verbose) way to say it while also illuminating "host" would be:
informs browsers that the host (identified by its domain name, and optionally its subdomains) should only be accessed using HTTPS
It introduces too many thoughts in the sentence though. Alternatively, it is technically a little sloppy but gets right to the point:
informs browsers that the domain name (and optionally its subdomains) should only be accessed using HTTPS
A third option would be to add another sentence explaining it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a good question. I suppose the point is that host and domain name are not the same thing: host is a server, domain name is its name (how it is identified).
informs browsers that the host (identified by its domain name, and optionally its subdomains) should only be accessed using HTTPS
I mostly like this, although there's ambiguity in "and optionally its subdomains" - someone could think the subdomains are part of the things that identify the host. It's really more like: "host (identified by its domain name), and optionally its subdomains,". But I agree that this is too much for the first sentence.
informs browsers that the domain name (and optionally its subdomains) should only be accessed using HTTPS
I like this less because it's too inaccurate: a domain name isn't a thing you access.
Overall, I think just leaving this with "host" linked to the glossary is fine, and then describing how a host is identified in the Description section.
|
||
> [!NOTE] | ||
> This is more secure than configuring a HTTP to HTTPS ({{HTTPStatus("301")}}) redirect on your server, as the initial HTTP connection is still vulnerable to a man-in-the-middle attack. | ||
> HSTS should be used in addition to configuring an HTTP to HTTPS ({{HTTPStatus("301")}}) redirect on your server, as the initial HTTP connection is still vulnerable to a man-in-the-middle attack. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't quite right. HSTS doesn't prevent the initial connection being vulnerable either unless the browser has the preload list set up.
The original text is more like "using HSTS will always force the upgrade after first connection, and this is more safe that using a server redirect. I am not sure why that is true, other than perhaps the facility to prevent any other kinds of bypasses such as accepting poor certificates, so I think your structure is better.
> HSTS should be used in addition to configuring an HTTP to HTTPS ({{HTTPStatus("301")}}) redirect on your server, as the initial HTTP connection is still vulnerable to a man-in-the-middle attack. | |
> HSTS should be used in addition to configuring an HTTP to HTTPS ({{HTTPStatus("301")}}) redirect on your server. | |
> The initial HTTP connection is still vulnerable to a man-in-the-middle attack, but this can be mitigated using a browser HSTS preload list. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I believe the original text was trying to explain why a redirect to HTTPS alone is insufficient (since this has long been a practice even before HSTS was introduced), but the way it was worded could be misread to imply that they are mutually exclusive. I wanted to emphasize that both should be used (per RFC section 7.2), but when I rewrote the first clause I missed that the second clause ("as the...") becomes wrong, because it's introduced as a reason but does not supply a supporting reason to the first clause.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK. I'm hoping @wbamberg will look at this in the week. I'll try look at it again Friday.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should remove this note. It's a somewhat subtle point, and hard to express in a short note without either being misleading, or trying to pack too much into a short sentence, which makes it very hard to understand. Let's keep the preamble here to an overview of what HSTS itself does, and talk about the context in which it is used in the description, where we have the space to explain it all properly.
I agree with @vobarian that the likely intention of the original:
Note: This is more secure than configuring a HTTP to HTTPS (301) redirect on your server, as the initial HTTP connection is still vulnerable to a man-in-the-middle attack.
is "This is more secure than only configuring a HTTP to HTTPS (301) redirect ", and I think your version is definitely better, but it is (I think) going to be hard for people to understand, and doesn't account for the case of first-ever (or first-after-HSTS-expiry) connection.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. I thought the original note box was awkward so high on the page. I'll look into incorporating the redirect recommendation into the description.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I did wonder while writing my review if we ought to have some explicit stuff about using this header in tandem with redirection, and I think it might help some of the stuff discussed below about the "Threat models" section. But that's more extensive surgery than we may want to contemplate :).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wbamberg I've given this a quick scan and will have a more thorough look tomorrow. As you've just gone around the loop on this topic, would you be interested in looking too?
Preview URLs Flaws (3)URL:
(comment last updated: 2025-06-19 00:10:47) |
…h redirect Co-authored-by: Hamish Willee <[email protected]>
files/en-us/web/http/reference/headers/strict-transport-security/index.md
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I think this is much better.
files/en-us/web/http/reference/headers/strict-transport-security/index.md
Outdated
Show resolved
Hide resolved
files/en-us/web/http/reference/headers/strict-transport-security/index.md
Outdated
Show resolved
Hide resolved
|
||
When the expiration time specified by the `Strict-Transport-Security` header elapses, the next request to the host via HTTP will proceed with insecure HTTP instead of automatically using HTTPS. Whenever the `Strict-Transport-Security` header is delivered to the browser, it will update the expiration time for that host. | ||
Using a fixed value for `max-age` can prevent the HSTS policy from expiring, as each subsequent response will push the expiration farther into the future. | ||
Should it be necessary to disable Strict Transport Security, setting `max-age=0` (over an HTTPS connection) will immediately expire the HSTS policy, allowing access via HTTP. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it be necessary to disable Strict Transport Security, setting `max-age=0` (over an HTTPS connection) will immediately expire the HSTS policy, allowing access via HTTP. | |
To disable Strict Transport Security, setting `max-age=0` (over an HTTPS connection) will immediately expire the HSTS policy, allowing access via HTTP. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels a little grammatically off. I think "To disable," sets up an imperative clause. (The original wording wasn't mine either.) What about just removing the latter part?
To disable Strict Transport Security, set
max-age=0
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, or if we did want to keep the second part:
To disable Strict Transport Security, set max-age=0: this will immediately...
files/en-us/web/http/reference/headers/strict-transport-security/index.md
Outdated
Show resolved
Hide resolved
- `includeSubDomains` {{optional_inline}} | ||
- : If this optional parameter is specified, this rule applies to all of the site's subdomains as well. | ||
- : If this optional directive is specified, the HSTS policy applies to all subdomains of the host's domain as well. | ||
- `preload` {{optional_inline}} {{non-standard_inline}} | ||
- : See [Preloading Strict Transport Security](#preloading_strict_transport_security) for details. When using `preload`, the `max-age` directive must be at least `31536000` (1 year), and the `includeSubDomains` directive must be present. | ||
Not part of the specification. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not part of the specification. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with removing it (I didn't write it), but it does seem relevant to me. It is a vendor extension. Is it just considered too much detail?
Perhaps also worth noting for the preload info in this page overall, the https://hstspreload.org/ site itself says in bold, "HSTS preloading is not recommended."
Perhaps on this page it should be more of a footnote, or just link out to that site?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with removing it (I didn't write it), but it does seem relevant to me. It is a vendor extension. Is it just considered too much detail?
Just that it's already indicated, by the little warning icon. This isn't very clear: however, it means we have a defined mechanism for representing nonstandard, which we have tooling to maintain: if it became standardized, we would almost automatically remove the icon, but not any free-form text.
Perhaps also worth noting for the preload info in this page overall, the https://hstspreload.org/ site itself says in bold, "HSTS preloading is not recommended."
That's very interesting, especially the stuff about Chrome/Safari just always upgrading (I use Firefox, which doesn't, so I didn't know this). I do think this should be noted in this page.
### How the browser handles Strict Transport Security | ||
|
||
When an HTTPS response includes the `Strict-Transport-Security` header, the browser adds the host's domain name | ||
to its persistent list of non-expired Known HSTS Hosts. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to its persistent list of non-expired Known HSTS Hosts. | |
to its list of HSTS hosts. |
(here and elsewhere) I think you can simplify this. "Known HSTS Host" is a spec term and this section would make just as much sense if it uses the term "HSTS host". We don't need to say the list is persistent, this is surely obvious. And I'm not sure of the value in talking about a list of "non-expired Known HSTS Hosts", sure if it's expired it's not an HSTS host any more, by definition?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough. I tried to represent the RFC accurately, but it may be too precise for a summary page like this. I included "non-expired" specifically in reference to section 8.1, which uses a whole paragraph to say as much about the max-age=0 case. But this doc also covers the case later in the paragraph about expirations, so I agree common sense can suffice.
"Persistent" being obvious I'm not so sure of. It is obvious to us, but I try to think from the perspective of an audience that has never heard of this before. Most HTTP headers are intrinsically stateless, and affect only the current request. I added "persistent" to introduce into the reader's mind the fact that this is a stateful mechanism. I'm still OK with removing it though, if you want, as I agree most people will figure it out.
files/en-us/web/http/reference/headers/strict-transport-security/index.md
Outdated
Show resolved
Hide resolved
files/en-us/web/http/reference/headers/strict-transport-security/index.md
Outdated
Show resolved
Hide resolved
|
||
Strict Transport Security resolves this problem; as long as you've accessed your bank's website once using HTTPS, and the bank's website uses Strict Transport Security, your browser will know to automatically use only HTTPS, which prevents hackers from performing this sort of man-in-the-middle attack. | ||
With HSTS, as long as at least one secure connection has been made to the host in the past and the `Strict-Transport-Security` response header was present, the browser remembers it as a Known HSTS Host, and the connection uses HTTPS before a man-in-the-middle attack has a chance to occur. However, the HSTS header alone cannot protect an initial insecure request if the browser has never before connected to the host and so does not have the domain name in its Known HSTS Hosts list. [Preloading](#preloading_strict_transport_security) can mitigate this problem. For the same reason, it is still important to specify the `https` scheme in URLs even when using HSTS. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With HSTS, as long as at least one secure connection has been made to the host in the past and the
Strict-Transport-Security
response header was present, the browser remembers it as a Known HSTS Host, and the connection uses HTTPS before a man-in-the-middle attack has a chance to occur.
This is not 100% correct as it doesn't account for HSTS expiry. Also "man"->"manipulator", and "occur" is a very passive way to describe an attack.
Maybe something like:
With HSTS, as long as at least one secure connection has been made to the host in the past and the `Strict-Transport-Security` response header was present, the browser remembers it as a Known HSTS Host, and the connection uses HTTPS before a man-in-the-middle attack has a chance to occur. However, the HSTS header alone cannot protect an initial insecure request if the browser has never before connected to the host and so does not have the domain name in its Known HSTS Hosts list. [Preloading](#preloading_strict_transport_security) can mitigate this problem. For the same reason, it is still important to specify the `https` scheme in URLs even when using HSTS. | |
Once the browser recognises the host as an HSTS host, then all connections will use HTTPS from the beginning, even if the URL uses the HTTP scheme. This prevents a MITM attack on the initial request. | |
However, the browser is still vulnerable to a MITM attack if the very first connection uses HTTP, because the browser will not yet have received the `Strict-Transport-Security` header, so it won't recognise the host as an HSTS host. The browser is also vulnerable if the `Strict-Transport-Security` header has expired. [Preloading](#preloading_strict_transport_security) can mitigate this problem. For the same reason, it is still important to specify the `https` scheme in URLs even when using HSTS. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good points. It's true that it doesn't account for expiry; I just thought that would be obvious since there is a paragraph about it, and the focus here is on the initial vs. subsequent requests. I can definitely work that in though. I like the brevity of what you wrote, but I do think it misses an essential point: "Once the browser recognises the host" doesn't specify the conditions for that to occur, whereas my versions does. However, I acknowledge it may not be necessary to give that information again here, as it is explained elsewhere on the page.
I think "remember" is more precise than "recognize", because "recognize" doesn't explain how, but "remember" highlights that it's simply state, again emphasizing the statefulness.
But the main thing I'm trying to make clear is the difference between the first ever connection (prior to the browser knowing it is an HSTS host) and subsequent connections. In your wording, the time related words are "from the beginning", "initial", "very first" -- but the last one actually means a different time than the first two.
I'll have to work on this some more later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just a suggestion, but in case it is helpful. I think "Threat models" isn't a great title: for one, it makes less sense if there is only one threat, which there is if we remove the HTTP-subresources threat. It's also very abstract. I would call this section "Mitigating Manipulator-in the Middle" or something, and structure it something like:
- HTTPS as a whole is an effective protection against MITM
- sites typically want to benefit from HTTPS while still supporting users who request pages using HTTP
- to do this they redirect HTTP requests to HTTPS
- in this situation the first HTTP connection request is still vulnerable to MITM, and this is what HSTS protects against
- with HSTS, as long as a site is recognized as an HSTS host, then the initial connection is also made over HTTPS
- there is still a potential vulnerability if the very first connection to a site is made over HTTP, before the site has had a chance to send the STS header (or, similarly, if the STS header has expired and the client connects using HTTP
- this is what the preload list is designed to address
"Once the browser recognises the host" doesn't specify the conditions for that to occur, whereas my versions does. However, I acknowledge it may not be necessary to give that information again here, as it is explained elsewhere on the page.
No, it doesn't, but as you say, these conditions are already described above.
files/en-us/web/http/reference/headers/strict-transport-security/index.md
Outdated
Show resolved
Hide resolved
Co-authored-by: wbamberg <[email protected]>
…dern mixed content restrictions
I'm removing myself from review - i.e. even though I will remain marked as a reviewer I'm only going to stay here to learn some new things. You two are doing a much better job on this than I would have. |
…e redirect note from preamble and threat model section
Ready for re-review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 I think this is great! Thanks @vobarian !
This is so much better. Thanks you 2! |
Thank you! |
Description
Motivation
Previous documentation lacked clarity and used ambiguous terms.
Additional details
https://www.rfc-editor.org/rfc/rfc6797
Related issues and pull requests
Fix #39042