Skip to content

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

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 95 additions & 5 deletions fetch.bs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -9062,6 +9070,88 @@ done only by navigations). The <a>fetch controller</a> is also used to
<a for=request>redirect mode</a> set to "<code>manual</code>".


<h3 id=sec-advice>Defining fields with a `<code>Sec-</code>` prefix</h3>

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

<p>This prohibition provides servers some assurance that a <em>browser</em> produced these
<a for=/>headers</a>. 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 <a>header</a>.

<p>The use of <a>forbidden request-headers</a> are most useful where servers need to make security
decisions about the value of those <a for=/>headers</a> on <a for=/>requests</a> that also include
<a for=/>credentials</a>.

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


<h4 id=sec-reasons>Reasons to use a `<code>Sec-</code>` prefix</h4>

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

<p id=sec-connection class=example>A [:Connection:] <a>header</a> with a value of
`<code>close</code>` causes the server to close a connection after producing a
<a for=/>response</a>. This is not a capability that <a>fetch</a> is intended to enable, making this
a natural choice for a <a>forbidden request-header</a>.

<p id=sec-ws-key class=example>The [:Sec-WebSocket-Key:] <a>header</a> is used on a
`<code>GET</code>` <a for=/>request</a> made during the WebSocket handshake. Using the
`<code>Sec-</code>` prefix for [:Sec-WebSocket-Key:] ensures that a server that does not check other
<a for=/>headers</a> (such as [:Upgrade:]) cannot be duped into
believing that a <a>fetch</a> is a WebSocket connection attempt.

<p>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.

<p id=why-sec-fetch-dest-is-sec class=example>The [:Sec-Fetch-Dest:] <a>header</a> might be used in
<a for=/>requests</a> both without <a for=/>credentials</a>. The decisions that a server makes using
[:Sec-Fetch-Dest:] can be security-relevant for an honest user agent, even for <a for=/>requests</a>
without credentials.


<h4 id=sec-not-ok>Reasons not to use a `<code>Sec-</code>` prefix</h4>

<p>That a <a>header</a> value might be needed to answer a <a>CORS-preflight request</a> is
<em>not</em> a sufficient reason to use a `<code>Sec-</code>` prefix; all <a>CORS-preflight
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:].
Copy link
Member

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.

Copy link
Contributor Author

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?


<p id=sec-purpose-no-sec class=example>The [:Sec-Purpose:] field tells a server that a
<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.
Copy link
Member

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.

Copy link
Contributor Author

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.


<p class=note>There are a number of <a for=/>headers</a> that use the `<code>Sec-</code>` prefix for
legacy reasons. Consistency with these existing <a for=/>headers</a> is not a reason to use the
`<code>Sec-</code>` prefix for new <a for=/>headers</a>.

<p id=sec-ch-no-sec class=example><a href=https://datatracker.ietf.org/doc/html/rfc8942>Client
hints</a> give a server the ability to adapt content. Making these <a>forbidden request-headers</a>
denies fetch callers the ability to access this adaptation capability unnecessarily.

<p>The `<code>Sec-</code>` prefix has no purpose for <a for=/>headers</a> that are exclusively used
for <a for=/>responses</a>. Only consider the application of the `<code>Sec-</code>` prefix <a
for=/>headers</a> that are used in <a for=/>requests</a>.

<p id=ws-sec-prefix class=example>The [:Sec-WebSocket-Accept:] <a>header</a> is a
<a for=/>response</a> <a>header</a> that is exclusively used for the
<a href=https://datatracker.ietf.org/doc/html/rfc6455#section-4>WebSocket handshake</a>. This
<a>header</a>has no need to use the `<code>Sec-</code>` prefix.


<h2 id=acknowledgments class=no-num>Acknowledgments</h2>

<p>Thanks to
Expand Down
Loading