-
Notifications
You must be signed in to change notification settings - Fork 352
Add usage advice for Sec- #1818
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
base: main
Are you sure you want to change the base?
Conversation
There are a lot of examples where the `Sec-` prefix is used without a lot of consideration for why. This change is an attempt to articulate why you might want to use this prefix and deny a website the ability to set a value for a header. Examples of `Sec-` that make the platform worse include `Sec-CH-` prefixed headers, which all engage server content negotiation capabilities that sites might be able to use. I would include `Sec-Browsing-Topics` in this category also, but maybe for more reasons than one. Examples that are mostly just pointless include `Sec-GPC` and `Sec-Purpose`, which both have no security-relevant decision that might be made by a server. The `Sec-Fetch-Dest` and `Sec-Fetch-Mode` headers are good examples of things that would have security consequences if they weren't prefixed. We also have a bunch that are forbidden and not prefixed that make a bunch of sense, like `Connection`. I make an argument for `Sec-WebSocket-Key` in the text, which seems pretty solid to me. I can't make a similar argument for the other websocket headers. `Sec-WebSocket-Accept` is a response-only header, so the prefix makes no sense other than for naming consistency, which is a bad reason. Part of the reason for this is that we're seeing a bunch of cargo-culting in the definition of headers. Take device-bound session credentials (https://github.com/w3c/webappsec-dbsc), which defines a response header called `Sec-Session-Registration`. There, the reason appears to be consistency with request header naming, but it's not clear that the request headers themselves need a `Sec-` prefix either.
I am interested in your example
(To double-check, this is not an example of the advice directly above it about CORS preflights, right? It's just coincidentally right after that, as something else you don't agree with.) I think this falls into a general category where servers are better served by getting accurate information about the purpose of a request, but indeed getting inaccurate information isn't a security problem. (At least, not a security problem more serious than a DOS.) In such cases, I've advised spec writers that using A recent example is our design of
There's also somewhat of a self-reinforcing argument here, because it could be confusing for servers to receive a request with |
I thought that that would attract comment :)
Yeah, I struggled with the transition there. It's coincidental positioning only. I have heard a number of people who say that they received advice about the Your example of speculation is one where the harm isn't obvious. Why would an app want to trigger a fetch marked as prefetch? If you can't imagine a reason, there's a tendency to slap a (Of course, the need for a preflight could make the prefetch too slow to be useful, but that's a separate problem.) |
Martin, thanks for writing this up - Another reason that we liked using Sec- for Storage-Access Headers was that the Sec- namespace is automatically reserved by virtue of the entire prefix being forbidden, making conflicts with existing custom application headers impossible. Do you have any thoughts on that and should we consider this in advice we give to browser developers? |
I don't know what you mean by reserved here. If you mean reserved for this purpose (and not some other purpose), that is why we have IANA registries. The storage access headers appear to be registered, so that's probably not it... (That's not true for a few other headers that others have started to use. Including Reserving a header for the exclusive use of a user agent is somewhat appealing as a user agent developer. You say "mine" and that's the end of the story. No further thought. But adopting that position as a default denies sites the option to use the header. That's probably OK for |
I mean it's impossible to have prior usage of this header on the web, which avoids the pain of finding out whether you're going to break someone's site with it. |
My understanding is that - for new headers like this - HTTP archive is the benchmark. Are you talking about saving one query to that database? |
Co-authored-by: Mike West <mike@mikewest.org>
Co-authored-by: Mike West <mike@mikewest.org>
HTTP Archive covers public traffic, i.e. non-logged in scenarios and non-enterprise. This is a great suggestion but I'm not sure it's sufficient, it's certainly not the same as "literally guaranteed to have no prior usage on the Web". Given that we have a simple mechanism that can make that guarantee for both browsers and servers, why not use it? |
Is avoiding breaking even a single site really a reasonable goal here, considering that a site can also change its private use if there is a clash? Many new headers have been introduced without a |
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.
If we are going to redefine what it means to extend the same-origin policy we should not do that here.
requests</a> include [:Access-Control-Request-Method:], which is [=forbidden | ||
request-headers|forbidden=]. Any <a for=/>headers</a> that a fetch caller sets will not be set on a | ||
<a>CORS-preflight request</a> made by an honest user agent; instead, these are listed in | ||
[:Access-Control-Request-Headers:]. |
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 not sure this is a compelling example as these were introduced prior to the introduction of the prefix.
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 disagree. It's quite a compelling example in that it is forbidden for a very good reason. (I don't know why you quoted the unrelated text about ACRH, is there a point you wanted to make there?
<a for=/>request</a> is speculative. A server might choose to avoid triggering side-effects while | ||
processing such a request, such as suppressing the recording of page view metrics. Making this a | ||
<a>forbidden request-header</a> has no security-relevant purpose and the `<code>Sec-</code>` prefix | ||
is therefore unnecessary. |
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 a redefinition of the threat model. See w3c/resource-hints#74 (comment) for a discussion of this header.
Sending new headers across origin without preflight and without a Sec-
prefix is an extension of the same-origin policy.
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, I traced the origin of Sec-Purpose to that thread. You do not establish a reason for it being forbidden, but instead assume that to be the case. If there was a risk that a server might be confused by the presence of the field, that would have been obvious. That case was not made, only asserted without evidence.
Sending new headers has to be safe in HTTP. We routinely add new headers in the IETF and have not encountered significant problems from having done so. Obviously, there is always a risk of collision, but we have things like the HTTP archive to aid in identifying potential conflicts. The point about preflight is only relevant if there is a) a conflict, b) a security-relevant decision being made that relies on the values being correct, and c) a resource that has harmful side effects on requests that are not already subject to preflight. That's a pretty tight set of conditions.
I can make a clear case for Sec-Fetch-Dest as it pertains to JSONP (perhaps) and maybe some forms of script inclusion.. That clearly justifies the use of a prefix.
I agree with Anne's point about sending new headers across origins being an SOP issue and I like that this formulates a clear objective rule to follow here. I think it also makes it more clear to me what made me uneasy about this PR - it tries to impose a subjective decision upon browser developers to take their best guess on whether or not their header could be security relevant - with a bias towards not adding the @martinthomson it would be good if you could clearly formulate your reasons for wanting to stop people from "cargo-culting" on From a security standpoint, there should be clear rules though, and I support the threat model that Anne puts forward here. |
@annevk I find your claim about SOP confusing. This has very little to do with SOP or the security model. I'm not looking to change the definition of @johannhof The pull request makes the case pretty clearly already. Maybe you disagree. The problem is that denying script the option to request content with forbidden fields forces the use of alternative spellings of the exact same semantics. Consider Sec-CH-DPR. Is there any security reason why a site should not be permitted to request content with a higher DPR than the screen on which the browser assumes it might be displayed? I don't know that a threat model has been documented, but I don't think that the one you both seem to have settled on is useful. If we consider preflight to be effective in blunting the effectiveness of attacks, and that preflight is included whenever a non-safelisted field is added to a request (at least when using the API; by the way, there is a reason that people always end up asking @annevk to interpret this specification, I had a really hard time working this out; I'm still not confident that I've 100% covered that). There are then no cases where an "attacker"-controlled request appears without first getting permission from the resource. More fundamentally, if new fields cannot be sent to servers, we have a major problem. New fields are defined all the time. There can be good reasons for browsers to send them. They will appear in form submissions. There's a good reason that the list of forbidden fields includes old fields, because those are more likely to be acted upon by servers that are not aware of CORS. But for new fields defined so long after CORS became ubiquitous, it's silly to insist that a server might act on it in a way that can be exploited. The threat model I documented is - at least in my view - a clearer one. That is, if a server needs to make a security-relevant decision with confidence that the value of the |
@martinthomson I don't believe that it is possible to objectively and completely define "needs" and "security-relevant" in this sentence. One origin should just not be able to manipulate state that another origin expects to receive from the user agent, like permission state. I think I agree that there are cases where we can decide to make an explicit exception to this principle, maybe DPR is one of those, but that's the way we should approach this question, not the other way around. |
There are a lot of examples where the
Sec-
prefix is used without a lot of consideration for why.This change is an attempt to articulate why you might want to use this prefix and deny a website the ability to set a value for a header.
Examples of
Sec-
that make the platform worse includeSec-CH-
prefixed headers, which all engage server content negotiation capabilities that sites might be able to use. I would includeSec-Browsing-Topics
in this category also, but maybe for more reasons than one.Examples that are mostly just pointless include
Sec-GPC
andSec-Purpose
, which both have no security-relevant decision that might be made by a server.The
Sec-Fetch-Dest
andSec-Fetch-Mode
headers are good examples of things that would have security consequences if they weren't prefixed. We also have a bunch that are forbidden and not prefixed that make a bunch of sense, likeConnection
.I make an argument for
Sec-WebSocket-Key
in the text, which seems pretty solid to me. I can't make a similar argument for the other websocket headers.Sec-WebSocket-Accept
is a response-only header, so the prefix makes no sense other than for naming consistency, which is a bad reason.Part of the reason for this is that we're seeing a bunch of cargo-culting in the definition of headers. Take device-bound session credentials (https://github.com/w3c/webappsec-dbsc), which defines a response header called
Sec-Session-Registration
. There, the reason appears to be consistency with request header naming, but it's not clear that the request headers themselves need aSec-
prefix either.Preview | Diff