From d866a02614637986b86245b80e40685e37e39740 Mon Sep 17 00:00:00 2001 From: Mike West Date: Tue, 30 Apr 2024 14:27:22 +0000 Subject: [PATCH] Define `Sec-Fetch-Frame-Ancestors`. This patch aims to formalize the discussion from w3c/webappsec-fetch-metadata#56, defining a `Sec-Fetch-Frame-Ancestors` header that supplements `Sec-Fetch-Site`'s exposure of the relationship between a request's initiator and the request's target with additional context about the same-siteness of context within which the request was made. This should support developers' understanding of the viability of various `SameSite` cookie settings on the one hand, and the ways in which their resources are partitioned on the other. --- index.bs | 111 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 94 insertions(+), 17 deletions(-) diff --git a/index.bs b/index.bs index eb37b90..7116d9c 100644 --- a/index.bs +++ b/index.bs @@ -13,6 +13,7 @@ Abstract: enough information to make a priori decisions about whether or not to service a request based on the way it was made, and the context in which it will be used. Markup Shorthands: markdown yes +Issue Tracking: Github https://github.com/w3c/webappsec-fetch-metadata/issues/new !Participate: File an issue (open issues) !Tests: web-platform-tests fetch/sec-metadata/ Version History: https://github.com/w3c/webappsec-fetch-metadata/commits/main/index.bs @@ -87,11 +88,12 @@ proxies, CDNs, etc) if desired. Examples {#examples} -------------------- -A request generated by a <{picture}> element would result in a request containing the following +A request generated by a <{picture}> element might result in a request containing the following HTTP request headers: ``` Sec-Fetch-Dest: image +Sec-Fetch-Frame-Ancestors: cross-site Sec-Fetch-Mode: no-cors Sec-Fetch-Site: cross-site ``` @@ -165,6 +167,69 @@ To set the `Sec-Fetch-Dest` header for a [= +The `Sec-Fetch-Frame-Ancestors` HTTP Request Header {#sec-fetch-frame-ancestors-header} +--------------------------------------------------------------------------------------- + +The `Sec-Fetch-Frame-Ancestors` HTTP request header exposes the +relationship between a [=request=]'s initiator's origin, its target origin, and the origins of +the chain of ancestor documents that embed the initiator. It is a [=Structured Header=] whose +value is a [=structured header/token=]. [[!I-D.ietf-httpbis-header-structure]] Its ABNF is: + +``` +Sec-Fetch-Frame-Ancestors = sh-token +``` + +Valid `Sec-Fetch-Frame-Ancestors` values include "`cross-site`", "`same-origin`", "`same-site`", +and "`none`". In order to support forward-compatibility with as-yet-unknown request types, +servers SHOULD ignore this header if it contains an invalid value. + +Note: This header is delivered for all requests other than top-level navigations. Those are +identifiable by examining the ``Sec-Fetch-Dest``header's value, so we +can safely omit this header as it would be fully redundant in that case. + +
+To set the `Sec-Fetch-Frame-Ancestors` header for a [=request=] |r|: + +
    + 1. Assert: |r|'s [=request/url=] is a [=potentially trustworthy URL=]. + + 2. If |r|'s [=request/destination=] is "`document`", return. + + 3. Let |header| be a [=Structured Header=] whose value is a [=structured header/token=]. + + 3. Set |header|'s value to "`same-origin`".. + + 4. Let |site| be the result of determining |r|'s site value. + + 5. Switch on |site|, and run the associated steps: + + : "`none`" + :: Set |header|'s value to "`none`". + : "`cross-site`" + :: Set |header|'s value to "`cross-site`". + : "`same-site`" + : "`same-origin`" + :: For each |ancestor| in |r|'s [=request/client=]'s [=environment settings object/global object=]'s + [=associated `Document`=]'s [=Document/inclusive ancestor navigables=]: + + 1. Let |ancestor origin| be |ancestor|'s [=navigable/active document=]'s [=Document/origin=]. + + 2. If |ancestor origin| is not [=same site=] with |r|'s [=request/origin=], set |header|'s value + to "`cross-site`", and [=iteration/break=]. + + 3. If |ancestor origin| is not [=same origin=] with |r|'s [=request/origin=], set |header|'s value + to "`same-site`", and [=iteration/break=]. + + Note: We're relying on the fact that determine a request's site value walks the + redirect chain, and the output can be "`same-site`" or "`same-origin`" only in cases where the + request's client is same-origin or same-site with each item in the chain. The only things we + need to compare, then, are the ancestor chain and the request's request/origin. + + 6. [=header list/Set a structured field value=] + ``Sec-Fetch-Frame-Ancestors``/|header| in |r|'s [=request/header list=]. +
+
+ The `Sec-Fetch-Mode` HTTP Request Header {#sec-fetch-mode-header} ----------------------------------------------------------------- @@ -212,33 +277,43 @@ Valid `Sec-Fetch-Site` values include "`cross-site`", "`same-origin`", "`same-si In order to support forward-compatibility with as-yet-unknown request types, servers SHOULD ignore this header if it contains an invalid value. -
-To set the `Sec-Fetch-Site` header for a [=request=] |r|: +
+To determine a request's site value for a [=request=] |r|:
    - 1. Assert: |r|'s [=request/url=] is a [=potentially trustworthy URL=]. - - 2. Let |header| be a [=Structured Header=] whose value is a [=structured header/token=]. - - 3. Set |header|'s value to `same-origin`. + 1. Let |result| be "`same-origin`". - 4. If |r| is a [=navigation request=] that was explicitly caused by a user's interaction with + 2. If |r| is a [=navigation request=] that was explicitly caused by a user's interaction with the user agent (by typing an address into the user agent directly, for example, or by - clicking a bookmark, etc.), then set |header|'s value to `none`. + clicking a bookmark, etc.), then set |result| to "`none`". Note: See [[#directly-user-initiated]] for more detail on this somewhat poorly-defined step. - 5. If |header|'s value is not `none`, then for each |url| in |r|'s [=request/url list=]: + 3. If |result| is not "`none`", then for each |url| in |r|'s [=request/url list=]: 1. If |url| is [=same origin=] with |r|'s [=request/origin=], [=iteration/continue=]. - 2. Set |header|'s value to `cross-site`. + 2. Set |result| to "`cross-site`". 3. If |r|'s [=request/origin=] is not [=same site=] with |url|'s [=url/origin=], then [=iteration/break=]. - 4. Set |header|'s value to `same-site`. + 4. Set |result| to "`same-site`". - 6. [=header list/Set a structured field value=] + 4. Return |result|. +
+
+ +
+To set the `Sec-Fetch-Site` header for a [=request=] |r|: + +
    + 1. Assert: |r|'s [=request/url=] is a [=potentially trustworthy URL=]. + + 2. Let |header| be a [=Structured Header=] whose value is a [=structured header/token=]. + + 3. Set |header|'s value to the result of determining |r|'s site value. + + 4. [=header list/Set a structured field value=] ``Sec-Fetch-Site``/|header| in |r|'s [=request/header list=].
@@ -298,11 +373,13 @@ To append the Fetch metadata headers for a request 2. Set the `Sec-Fetch-Dest` header for |r|. - 3. Set the `Sec-Fetch-Mode` header for |r|. + 3. Set the `Sec-Fetch-Frame-Ancestors` header for |r|. + + 4. Set the `Sec-Fetch-Mode` header for |r|. - 4. Set the `Sec-Fetch-Site` header for |r|. + 5. Set the `Sec-Fetch-Site` header for |r|. - 5. Set the `Sec-Fetch-User` header for |r|. + 6. Set the `Sec-Fetch-User` header for |r|.