From c8dcd8413e1e0793eaef2a217945a06ed04f80f2 Mon Sep 17 00:00:00 2001 From: Martin Thomson Date: Mon, 31 Mar 2025 17:17:36 +1100 Subject: [PATCH 1/4] Add usage advice for Sec- 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. --- fetch.bs | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 95 insertions(+), 5 deletions(-) diff --git a/fetch.bs b/fetch.bs index adee889ba..a878607df 100644 --- a/fetch.bs +++ b/fetch.bs @@ -22,11 +22,15 @@ urlPrefix:https://httpwg.org/specs/rfc9651.html#;type:dfn;spec:rfc9651 url:;text:structured header url:token;text:structured field token -urlPrefix:https://httpwg.org/specs/rfc9110.html#;type:dfn;spec:http - url:method.overview;text:method - url:fields.names;text:field-name - url:fields.values;text:field-value - url:rfc.section.9.2.1;text:unsafe +urlPrefix:https://httpwg.org/specs/rfc9110.html#;spec:http + type:dfn + url:method.overview;text:method + url:fields.names;text:field-name + url:fields.values;text:field-value + url:rfc.section.9.2.1;text:unsafe + type:http-header + url:field.connection;text:Connection + url:field.upgrade;text:Upgrade urlPrefix:https://httpwg.org/specs/rfc9111.html#;type:dfn;spec:http-caching url:delta-seconds;text:delta-seconds @@ -41,6 +45,10 @@ urlPrefix:https://httpwg.org/specs/rfc9111.html#;type:dfn;spec:http-caching urlPrefix:https://httpwg.org/specs/rfc9112.html#;type:dfn;spec:http1 url:status.line;text:reason-phrase +url:https://datatracker.ietf.org/doc/html/rfc6455;type:http-header;spec:websocketprotocol + text:Sec-WebSocket-Accept + text:Sec-WebSocket-Key + url:https://w3c.github.io/resource-timing/#dfn-mark-resource-timing;text:mark resource timing;type:dfn;spec:resource-timing urlPrefix:https://w3c.github.io/hr-time/#;spec:hr-time @@ -9062,6 +9070,88 @@ done only by navigations). The fetch controller is also used to redirect mode set to "manual". +

Defining fields with a `Sec-` prefix

+ +

Fetch defines a set of forbidden request-headers and the `Sec-` prefix for +headers that are intended to be exclusively generated by the user agent. Callers of +fetch cannot set these values when making requests. + +

This prohibition provides servers some assurance that a browser produced these +headers. However, this assurance is limited to request that could only have been +generated by an honest user agent. Other types of application–including malicious browsers–can +provide any value for any header. + +

The use of forbidden request-headers are most useful where servers need to make security +decisions about the value of those headers on requests that also include +credentials. + +

Whether the value of forbidden request-headers can be trusted to be accurate then depends +on a judgment about the trustworthiness of the entity that is presenting +credentials. Any client or user agent acting on behalf of a malicious user might +present falsified information if that serves the user's interests. + + +

Reasons to use a `Sec-` prefix

+ +

It is not enough that a value originates from a user agent to justify the use of +`Sec-`, a server needs to depend on the accuracy of the information in the +header. When deciding whether to add a new header to the set of forbidden +request-headers by adding a `Sec-` prefix to its name, consider first whether a +server might make a security decision that relies on an accurate header value. + +

A [:Connection:] header with a value of +`close` causes the server to close a connection after producing a +response. This is not a capability that fetch is intended to enable, making this +a natural choice for a forbidden request-header. + +

The [:Sec-WebSocket-Key:] header is used on a +`GET` request made during the WebSocket handshake. Using the +`Sec-` prefix for [:Sec-WebSocket-Key:] ensures that a server that does not check other +headers (such as [:Upgrade:]) cannot be duped into +believing that a fetch is a WebSocket connection attempt. + +

Routine security checks can be aided as a result of having more accurate information, even if +there are cases where information might be spoofed by a malicious client. + +

The [:Sec-Fetch-Dest:] header might be used in +requests both without credentials. The decisions that a server makes using +[:Sec-Fetch-Dest:] can be security-relevant for an honest user agent, even for requests +without credentials. + + +

Reasons not to use a `Sec-` prefix

+ +

That a header value might be needed to answer a CORS-preflight request is +not a sufficient reason to use a `Sec-` prefix; all CORS-preflight +requests include [:Access-Control-Request-Method:], which is [=forbidden +request-headers|forbidden=]. Any headers that a fetch caller sets will not be set on a +CORS-preflight request made by an honest user agent; instead, these are listed in +[:Access-Control-Request-Headers:]. + +

The [:Sec-Purpose:] field tells a server that a +request 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 +forbidden request-header has no security-relevant purpose and the `Sec-` prefix +is therefore unnecessary. + +

There are a number of headers that use the `Sec-` prefix for +legacy reasons. Consistency with these existing headers is not a reason to use the +`Sec-` prefix for new headers. + +

Client +hints give a server the ability to adapt content. Making these forbidden request-headers +denies fetch callers the ability to access this adaptation capability unnecessarily. + +

The `Sec-` prefix has no purpose for headers that are exclusively used +for responses. Only consider the application of the `Sec-` prefix headers that are used in requests. + +

The [:Sec-WebSocket-Accept:] header is a +response header that is exclusively used for the +WebSocket handshake. This +headerhas no need to use the `Sec-` prefix. + +

Acknowledgments

Thanks to From fbbb9bfbb2ce9d635f1c74e096a6d91687c80e34 Mon Sep 17 00:00:00 2001 From: Martin Thomson Date: Tue, 1 Apr 2025 20:04:13 +1100 Subject: [PATCH 2/4] with or without Co-authored-by: Mike West --- fetch.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fetch.bs b/fetch.bs index a878607df..9ffbc64f7 100644 --- a/fetch.bs +++ b/fetch.bs @@ -9114,7 +9114,7 @@ believing that a fetch is a WebSocket connection attempt. there are cases where information might be spoofed by a malicious client.

The [:Sec-Fetch-Dest:] header might be used in -requests both without credentials. The decisions that a server makes using +requests both with or without credentials. The decisions that a server makes using [:Sec-Fetch-Dest:] can be security-relevant for an honest user agent, even for requests without credentials. From 83a388ee5d04145226422c0d5ee360eda09e6b6d Mon Sep 17 00:00:00 2001 From: Martin Thomson Date: Tue, 1 Apr 2025 20:04:39 +1100 Subject: [PATCH 3/4] Fewer words is better Co-authored-by: Mike West --- fetch.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fetch.bs b/fetch.bs index 9ffbc64f7..627181f83 100644 --- a/fetch.bs +++ b/fetch.bs @@ -9081,7 +9081,7 @@ done only by navigations). The fetch controller is also used to generated by an honest user agent. Other types of application–including malicious browsers–can provide any value for any header. -

The use of forbidden request-headers are most useful where servers need to make security +

Forbidden request-headers are most useful where servers need to make security decisions about the value of those headers on requests that also include credentials. From 476e808d113f17674d460f012b5f8510b3d11f18 Mon Sep 17 00:00:00 2001 From: Martin Thomson Date: Wed, 2 Apr 2025 21:25:57 +1100 Subject: [PATCH 4/4] spac e Co-authored-by: Simon Pieters --- fetch.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fetch.bs b/fetch.bs index 627181f83..0ddc9d270 100644 --- a/fetch.bs +++ b/fetch.bs @@ -9149,7 +9149,7 @@ for=/>headers that are used in requests.

The [:Sec-WebSocket-Accept:] header is a response header that is exclusively used for the WebSocket handshake. This -headerhas no need to use the `Sec-` prefix. +header has no need to use the `Sec-` prefix.

Acknowledgments