From 8fcb0eebddd133c6d831c13f6d8dcac051c37612 Mon Sep 17 00:00:00 2001 From: Benjamin VanderSloot Date: Mon, 7 Nov 2022 12:40:20 -0500 Subject: [PATCH 1/6] Add unsafe-no-cors mode We identified a potential need for a more sustainable no-cors mode in discussion surrounding FedCM. The purpose is to create a browser-process priveleged mode that will not fail the Access-Control-Allow-Origin CORS checks while otherwise behaving like a normal CORS request. Here are the deviations I have made from cors mode to make unsafe-no-cors are: - do not perform the "CORS check" (ACAO/ACAC) - allow the request to set a new omit origin flag that forces omission of the Origin header - require a request to have a policy container specified (via the client is allowed) - require the service worker mode to not be all Because this is such an unsafe mode I added an explanation inline with the other definitions of request modes and a warning about concerns and hand-waves about the client's agent cluster. Happy to get feedback on this draft! --- fetch.bs | 59 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/fetch.bs b/fetch.bs index a5c2cb26c..a13bc933d 100644 --- a/fetch.bs +++ b/fetch.bs @@ -35,6 +35,7 @@ urlPrefix:https://w3c.github.io/hr-time/#;spec:hr-time type:typedef;url:dom-domhighrestimestamp;text:DOMHighResTimeStamp urlPrefix:https://tc39.es/ecma262/#;type:dfn;spec:ecma-262 + url:sec-agent-clusters;text:agent cluster url:realm;text:realm url:sec-list-and-record-specification-type;text:Record @@ -1773,7 +1774,7 @@ to not have to set request's referrer.

A request has an associated mode, which is "same-origin", "cors", "no-cors", -"navigate", or "websocket". Unless stated otherwise, it is +"navigate", "unsafe-no-cors" or "websocket". Unless stated otherwise, it is "no-cors".

@@ -1796,6 +1797,14 @@ to not have to set request's referrer.
"navigate"
This is a special mode used only when navigating between documents. +
"unsafe-no-cors" +
This is an especially dangerous special mode. It is to be used by user agents to allow requests + not resticted to CORS-safelisted methods and CORS-safelisted request-headers and not + return an opaque filtered response on success while still bypassing the CORS check. This + is deliberately not exposed in the {{RequestMode}}. To mitigate potential accidental misuse an + "unsafe-no-cors" request must have a policy container provided and must not have + a service-worker mode of "all". +
"websocket"
This is a special mode used only when establishing a WebSocket connection. @@ -1803,6 +1812,10 @@ to not have to set request's referrer.

Even though the default request mode is "no-cors", standards are highly discouraged from using it for new features. It is rather unsafe. + +

Using request mode "unsafe-no-cors" + is even more discouraged and unsafe than "no-cors". Any use of this mode must be in an + agent cluster associated with the user agent itself, not that of site content.

A request has an associated @@ -1969,6 +1982,13 @@ Unless stated otherwise, it is false.

This flag is for exclusive use by HTML's render-blocking mechanism. [[!HTML]] +

A request has an associated +omit origin flag. +Unless stated otherwise, it is unset. + +

This flag is for exclusive use by a request with mode +"unsafe-no-cors" to omit the `Origin` header. +


A request has an associated @@ -3073,18 +3093,21 @@ given a request request, run these steps:

  • Let serializedOrigin be the result of byte-serializing a request origin with request. -

  • If request's response tainting is "cors" or - request's mode is "websocket", then +

  • If request's mode is "websocket", then append (`Origin`, serializedOrigin) to request's header list. +

  • If request's response tainting is "cors" and + request's omit origin flag is not set, then + append (`Origin`, serializedOrigin) to + request's header list.

  • Otherwise, if request's method is neither `GET` nor - `HEAD`, then: + `HEAD` and request's omit origin flag is not set, then:

    1. -

      If request's mode is not "cors", +

      If request's mode is not "cors" or "unsafe-no-cors", then switch on request's referrer policy:

      @@ -3758,15 +3781,14 @@ Cross-Origin-Resource-Policy = %s"same-origin" / %s"same-site" / %s"cross-or

      To perform a cross-origin resource policy check, given an origin -origin, an environment settings object settingsObject, a string +origin, an policy container policyContainer, a string destination, a response response, and an optional boolean forNavigation, run these steps:

      1. Set forNavigation to false if it is not given. -

      2. Let embedderPolicy be settingsObject's - policy container's +

      3. Let embedderPolicy be policyContainer's embedder policy.

      4. @@ -4051,7 +4073,7 @@ the request. HTTP(S) scheme
      5. request's mode is "same-origin", - "cors", or "no-cors" + "cors", "unsafe-no-cors", or "no-cors"

      6. request's window is not null @@ -4094,6 +4116,9 @@ the request. clone of request's client's policy container. [[!HTML]] +

      7. Assert: request's mode is not + "unsafe-no-cors". +

      8. Otherwise, set request's policy container to a new policy container.

      @@ -4174,6 +4199,10 @@ steps: current URL is not local, then set response to a network error. +
    2. If request's omit origin flag is set and request's + mode is not "unsafe-no-cors" then set response to a + network error. +

    3. Run report Content Security Policy violations for request.

    4. Upgrade request to a potentially trustworthy URL, if appropriate. @@ -4717,6 +4746,8 @@ these steps:

      If request's service-workers mode is "all", then:

        +
      1. Assert: request's mode is not "unsafe-no-cors". +

      2. Let requestForServiceWorker be a clone of request. @@ -4788,6 +4819,8 @@ these steps:

      3. request's mode is not "no-cors" and response's type is "opaque" +

      4. request's mode is "unsafe-no-cors" +

      5. request's redirect mode is not "manual" and response's type is "opaqueredirect" @@ -4846,7 +4879,8 @@ these steps: HTTP-network-or-cache fetch given fetchParams.
      6. -

        If request's response tainting is "cors" and a +

        If request's response tainting is "cors", + request's mode is not "unsafe-no-cors", and a CORS check for request and response returns failure, then return a network error. @@ -4862,7 +4896,7 @@ these steps:

        If either request's response tainting or response's type is "opaque", and the cross-origin resource policy check with request's origin, - request's client, request's + request's policy container, request's destination, and actualResponse returns blocked, then return a network error. @@ -4940,7 +4974,7 @@ run these steps:

      7. Increase request's redirect count by one. -

      8. If request's mode is "cors", +

      9. If request's mode is "cors" or "unsafe-no-cors", locationURL includes credentials, and request's origin is not same origin with locationURL's origin, then return a network error. @@ -8303,6 +8337,7 @@ Axel Rauschmayer, Ben Kelly, Benjamin Gruenbaum, Benjamin Hawkes-Lewis, +Benjamin VanderSloot, Bert Bos, Björn Höhrmann, Boris Zbarsky, From ae04837e61dac31d30164dc49ae1148bf63fda0b Mon Sep 17 00:00:00 2001 From: Benjamin VanderSloot Date: Mon, 14 Nov 2022 16:12:39 -0500 Subject: [PATCH 2/6] Make first round of changes "stable no-cors" vision --- fetch.bs | 71 +++++++++++++++++++++++++------------------------------- 1 file changed, 32 insertions(+), 39 deletions(-) diff --git a/fetch.bs b/fetch.bs index a13bc933d..da461b5eb 100644 --- a/fetch.bs +++ b/fetch.bs @@ -36,6 +36,7 @@ urlPrefix:https://w3c.github.io/hr-time/#;spec:hr-time urlPrefix:https://tc39.es/ecma262/#;type:dfn;spec:ecma-262 url:sec-agent-clusters;text:agent cluster + url:host-environment;text:host environment url:realm;text:realm url:sec-list-and-record-specification-type;text:Record @@ -1774,8 +1775,8 @@ to not have to set request's referrer.

        A request has an associated mode, which is "same-origin", "cors", "no-cors", -"navigate", "unsafe-no-cors" or "websocket". Unless stated otherwise, it is -"no-cors". +"navigate", "unsafe-no-cors", or "websocket". +Unless stated otherwise, it is "no-cors".

        @@ -1798,12 +1799,13 @@ to not have to set request's referrer.
        This is a special mode used only when navigating between documents.
        "unsafe-no-cors" -
        This is an especially dangerous special mode. It is to be used by user agents to allow requests - not resticted to CORS-safelisted methods and CORS-safelisted request-headers and not - return an opaque filtered response on success while still bypassing the CORS check. This - is deliberately not exposed in the {{RequestMode}}. To mitigate potential accidental misuse an - "unsafe-no-cors" request must have a policy container provided and must not have - a service-worker mode of "all". +
        This is a special mode for the host environment to use internally to wittingly make + requests that are unsafe. It restricts requests to using CORS-safelisted methods and + CORS-safelisted request-headers. However, the request will not be required to pass a + cross-origin resource policy check or to test if + Cross-Origin-Embedder-Policy allows credentials. Additionally, upon success a fetch will + return a cors filtered response. However, a request with this mode cannot + use service-workers mode "all".
        "websocket"
        This is a special mode used only when @@ -1815,7 +1817,8 @@ to not have to set request's referrer.

        Using request mode "unsafe-no-cors" is even more discouraged and unsafe than "no-cors". Any use of this mode must be in an - agent cluster associated with the user agent itself, not that of site content. + agent cluster associated with the host environment itself to isolate its results from + misuse. This mode is deliberately not exposed in the {{RequestMode}}.

        A request has an associated @@ -1982,13 +1985,6 @@ Unless stated otherwise, it is false.

        This flag is for exclusive use by HTML's render-blocking mechanism. [[!HTML]] -

        A request has an associated -omit origin flag. -Unless stated otherwise, it is unset. - -

        This flag is for exclusive use by a request with mode -"unsafe-no-cors" to omit the `Origin` header. -


        A request has an associated @@ -3093,21 +3089,18 @@ given a request request, run these steps:

      10. Let serializedOrigin be the result of byte-serializing a request origin with request. -

      11. If request's mode is "websocket", then +

      12. If request's response tainting is "cors" or + request's mode is "websocket", then append (`Origin`, serializedOrigin) to request's header list. -

      13. If request's response tainting is "cors" and - request's omit origin flag is not set, then - append (`Origin`, serializedOrigin) to - request's header list.

      14. Otherwise, if request's method is neither `GET` nor - `HEAD` and request's omit origin flag is not set, then: + `HEAD`, then:

        1. -

          If request's mode is not "cors" or "unsafe-no-cors", +

          If request's mode is not "cors", then switch on request's referrer policy:

          @@ -3781,14 +3774,15 @@ Cross-Origin-Resource-Policy = %s"same-origin" / %s"same-site" / %s"cross-or

          To perform a cross-origin resource policy check, given an origin -origin, an policy container policyContainer, a string +origin, an environment settings object settingsObject, a string destination, a response response, and an optional boolean forNavigation, run these steps:

          1. Set forNavigation to false if it is not given. -

          2. Let embedderPolicy be policyContainer's +

          3. Let embedderPolicy be settingsObject's + policy container's embedder policy.

          4. @@ -4073,7 +4067,7 @@ the request. HTTP(S) scheme
          5. request's mode is "same-origin", - "cors", "unsafe-no-cors", or "no-cors" + "cors", "no-cors", or "unsafe-no-cors"

          6. request's window is not null @@ -4116,9 +4110,6 @@ the request. clone of request's client's policy container. [[!HTML]] -

          7. Assert: request's mode is not - "unsafe-no-cors". -

          8. Otherwise, set request's policy container to a new policy container.

          @@ -4199,10 +4190,6 @@ steps: current URL is not local, then set response to a network error. -
        2. If request's omit origin flag is set and request's - mode is not "unsafe-no-cors" then set response to a - network error. -

        3. Run report Content Security Policy violations for request.

        4. Upgrade request to a potentially trustworthy URL, if appropriate. @@ -4331,6 +4318,15 @@ steps:

        5. Return corsWithPreflightResponse.

        +
        request's mode is "unsafe-no-cors" +
        +
          +
        1. Set request's response tainting to + "basic". + +

        2. Return the result of running HTTP fetch given fetchParams. +

        +
        Otherwise
          @@ -4746,8 +4742,6 @@ these steps:

          If request's service-workers mode is "all", then:

            -
          1. Assert: request's mode is not "unsafe-no-cors". -

          2. Let requestForServiceWorker be a clone of request. @@ -4879,8 +4873,7 @@ these steps: HTTP-network-or-cache fetch given fetchParams.

          3. -

            If request's response tainting is "cors", - request's mode is not "unsafe-no-cors", and a +

            If request's response tainting is "cors" and a CORS check for request and response returns failure, then return a network error. @@ -4896,7 +4889,7 @@ these steps:

            If either request's response tainting or response's type is "opaque", and the cross-origin resource policy check with request's origin, - request's policy container, request's + request's client, request's destination, and actualResponse returns blocked, then return a network error. @@ -4974,7 +4967,7 @@ run these steps:

          4. Increase request's redirect count by one. -

          5. If request's mode is "cors" or "unsafe-no-cors", +

          6. If request's mode is "cors", locationURL includes credentials, and request's origin is not same origin with locationURL's origin, then return a network error. From fbf459d8247e7f537901d7fa89dbbd16ca6c851f Mon Sep 17 00:00:00 2001 From: Benjamin VanderSloot Date: Tue, 22 Nov 2022 10:22:47 -0500 Subject: [PATCH 3/6] Editorial changes in the mode definition. --- fetch.bs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/fetch.bs b/fetch.bs index da461b5eb..e04f4ea0d 100644 --- a/fetch.bs +++ b/fetch.bs @@ -41,6 +41,10 @@ urlPrefix:https://tc39.es/ecma262/#;type:dfn;spec:ecma-262 url:sec-list-and-record-specification-type;text:Record +

            +
             {
                 "HTTP": {
            @@ -1799,13 +1803,18 @@ Unless stated otherwise, it is "no-cors".
               
            This is a special mode used only when navigating between documents.
            "unsafe-no-cors" -
            This is a special mode for the host environment to use internally to wittingly make +
            This is a special mode for the [=user agent=] to use internally to wittingly make requests that are unsafe. It restricts requests to using CORS-safelisted methods and - CORS-safelisted request-headers. However, the request will not be required to pass a - cross-origin resource policy check or to test if - Cross-Origin-Embedder-Policy allows credentials. Additionally, upon success a fetch will - return a cors filtered response. However, a request with this mode cannot - use service-workers mode "all". + CORS-safelisted request-headers and a request with this mode cannot use + service-workers mode "all". However, the request will not be required to + pass a cross-origin resource policy check or to test if + Cross-Origin-Embedder-Policy allows credentials. Upon success a fetch will + return a cors filtered response. + +

            Using request mode "unsafe-no-cors" + is even more discouraged and unsafe than "no-cors". Any use of this mode must be in an + agent cluster associated with the host environment itself to isolate its results from + misuse. This mode is deliberately not exposed in the {{RequestMode}}.

            "websocket"
            This is a special mode used only when @@ -1815,10 +1824,7 @@ Unless stated otherwise, it is "no-cors".

            Even though the default request mode is "no-cors", standards are highly discouraged from using it for new features. It is rather unsafe. -

            Using request mode "unsafe-no-cors" - is even more discouraged and unsafe than "no-cors". Any use of this mode must be in an - agent cluster associated with the host environment itself to isolate its results from - misuse. This mode is deliberately not exposed in the {{RequestMode}}. +

            A request has an associated From 9a4f3432cdceaf6d03713f6faa4fae7e6fe03395 Mon Sep 17 00:00:00 2001 From: Benjamin VanderSloot Date: Wed, 30 Nov 2022 09:09:53 -0500 Subject: [PATCH 4/6] Further refining the definition of the mode and adding an assertion --- fetch.bs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/fetch.bs b/fetch.bs index e04f4ea0d..44bda3c0b 100644 --- a/fetch.bs +++ b/fetch.bs @@ -35,8 +35,6 @@ urlPrefix:https://w3c.github.io/hr-time/#;spec:hr-time type:typedef;url:dom-domhighrestimestamp;text:DOMHighResTimeStamp urlPrefix:https://tc39.es/ecma262/#;type:dfn;spec:ecma-262 - url:sec-agent-clusters;text:agent cluster - url:host-environment;text:host environment url:realm;text:realm url:sec-list-and-record-specification-type;text:Record

            @@ -1804,17 +1802,18 @@ Unless stated otherwise, it is "no-cors".
            "unsafe-no-cors"
            This is a special mode for the [=user agent=] to use internally to wittingly make - requests that are unsafe. It restricts requests to using CORS-safelisted methods and - CORS-safelisted request-headers and a request with this mode cannot use + requests that are unsafe. It restricts a request to using CORS-safelisted methods, + CORS-safelisted request-headers, and the request must have a parallel queue + task destination. A request with this mode cannot use service-workers mode "all". However, the request will not be required to pass a cross-origin resource policy check or to test if Cross-Origin-Embedder-Policy allows credentials. Upon success a fetch will return a cors filtered response.

            Using request mode "unsafe-no-cors" - is even more discouraged and unsafe than "no-cors". Any use of this mode must be in an - agent cluster associated with the host environment itself to isolate its results from - misuse. This mode is deliberately not exposed in the {{RequestMode}}. + is even more discouraged and unsafe than "no-cors". Any use of this mode must be + memory-isolated to the [=user agent=] to contain its results and prevent their disclosure or misuse. + This mode is deliberately not exposed in the {{RequestMode}}.

            "websocket"
            This is a special mode used only when @@ -4003,6 +4002,10 @@ the request.

            Assert: request's mode is "navigate" or processEarlyHintsResponse is null. +

            If fetchParams's request's mode is + "unsafe-no-cors": assert: fetchParams's + task destination is a parallel queue. +

            Processing of early hints (responses whose status is 103) is only vetted for navigations. From 7356349a62cd384c7f8e9965f06a8dcfdb02e495 Mon Sep 17 00:00:00 2001 From: Benjamin VanderSloot Date: Wed, 30 Nov 2022 11:08:57 -0500 Subject: [PATCH 5/6] First attempt at placing the Origin header under full control of "unsafe-no-cors" mode --- fetch.bs | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/fetch.bs b/fetch.bs index 44bda3c0b..169bf416a 100644 --- a/fetch.bs +++ b/fetch.bs @@ -1808,7 +1808,7 @@ Unless stated otherwise, it is "no-cors". service-workers mode "all". However, the request will not be required to pass a cross-origin resource policy check or to test if Cross-Origin-Embedder-Policy allows credentials. Upon success a fetch will - return a cors filtered response. + return a basic filtered response.

            Using request mode "unsafe-no-cors" is even more discouraged and unsafe than "no-cors". Any use of this mode must be @@ -1826,6 +1826,12 @@ Unless stated otherwise, it is "no-cors". +

            A request has an associated +omit origin flag. Unless stated otherwise it is unset. + +

            The omit origin flag only has effect when +request's mode is "unsafe-no-cors". +

            A request has an associated use-CORS-preflight flag. Unless stated otherwise, it is unset. @@ -3095,8 +3101,9 @@ given a request request, run these steps: with request.

          7. If request's response tainting is "cors" or - request's mode is "websocket", then - append (`Origin`, serializedOrigin) to + request's mode is "websocket" or + "unsafe-no-cors", then append + (`Origin`, serializedOrigin) to request's header list.

          8. @@ -4064,7 +4071,9 @@ the request. global object is a {{Window}} object; otherwise "no-window". -
          9. If request's origin is "client", then set +

          10. If request's origin is "client" and either + request's mode is not "unsafe-no-cors" or + and request's omit origin flag is unset, then set request's origin to request's client's origin. @@ -4091,7 +4100,8 @@ the request.

            1. Assert: request's origin is same origin with request's client's - origin. + origin or request's mode + is "unsafe-no-cors".

            2. Let onPreloadedResponseAvailable be an algorithm that runs the following step given a response response: set fetchParams's @@ -5180,7 +5190,9 @@ run these steps: httpRequest's header list.

            -
          11. Append a request `Origin` header for httpRequest. +

          12. If either request's mode is not "unsafe-no-cors" + or request's omit origin flag is not set, +

            append a request `Origin` header for httpRequest.

          13. Append the Fetch metadata headers for httpRequest. [[!FETCH-METADATA]] From ecbf1c510f9fe2e59cd89a354247fdd229da9b03 Mon Sep 17 00:00:00 2001 From: Benjamin VanderSloot Date: Mon, 16 Jan 2023 14:19:18 -0500 Subject: [PATCH 6/6] s/unsafe-no-cors/user-agent-no-cors/g --- fetch.bs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/fetch.bs b/fetch.bs index 169bf416a..bac7ede94 100644 --- a/fetch.bs +++ b/fetch.bs @@ -1777,7 +1777,7 @@ to not have to set request's referrer.

            A request has an associated mode, which is "same-origin", "cors", "no-cors", -"navigate", "unsafe-no-cors", or "websocket". +"navigate", "user-agent-no-cors", or "websocket". Unless stated otherwise, it is "no-cors".

            @@ -1800,7 +1800,7 @@ Unless stated otherwise, it is "no-cors".
            "navigate"
            This is a special mode used only when navigating between documents. -
            "unsafe-no-cors" +
            "user-agent-no-cors"
            This is a special mode for the [=user agent=] to use internally to wittingly make requests that are unsafe. It restricts a request to using CORS-safelisted methods, CORS-safelisted request-headers, and the request must have a parallel queue @@ -1810,7 +1810,7 @@ Unless stated otherwise, it is "no-cors". Cross-Origin-Embedder-Policy allows credentials. Upon success a fetch will return a basic filtered response. -

            Using request mode "unsafe-no-cors" +

            Using request mode "user-agent-no-cors" is even more discouraged and unsafe than "no-cors". Any use of this mode must be memory-isolated to the [=user agent=] to contain its results and prevent their disclosure or misuse. This mode is deliberately not exposed in the {{RequestMode}}. @@ -1830,7 +1830,7 @@ Unless stated otherwise, it is "no-cors". omit origin flag. Unless stated otherwise it is unset.

            The omit origin flag only has effect when -request's mode is "unsafe-no-cors". +request's mode is "user-agent-no-cors".

            A request has an associated use-CORS-preflight flag. Unless stated @@ -3102,7 +3102,7 @@ given a request request, run these steps:

          14. If request's response tainting is "cors" or request's mode is "websocket" or - "unsafe-no-cors", then append + "user-agent-no-cors", then append (`Origin`, serializedOrigin) to request's header list. @@ -4010,7 +4010,7 @@ the request. processEarlyHintsResponse is null.

            If fetchParams's request's mode is - "unsafe-no-cors": assert: fetchParams's + "user-agent-no-cors": assert: fetchParams's task destination is a parallel queue.

            Processing of early hints (responses whose status @@ -4072,7 +4072,7 @@ the request. "no-window".

          15. If request's origin is "client" and either - request's mode is not "unsafe-no-cors" or + request's mode is not "user-agent-no-cors" or and request's omit origin flag is unset, then set request's origin to request's client's origin. @@ -4085,7 +4085,7 @@ the request. HTTP(S) scheme

          16. request's mode is "same-origin", - "cors", "no-cors", or "unsafe-no-cors" + "cors", "no-cors", or "user-agent-no-cors"

          17. request's window is not null @@ -4101,7 +4101,7 @@ the request.

          18. Assert: request's origin is same origin with request's client's origin or request's mode - is "unsafe-no-cors". + is "user-agent-no-cors".

          19. Let onPreloadedResponseAvailable be an algorithm that runs the following step given a response response: set fetchParams's @@ -4337,7 +4337,7 @@ steps:

          20. Return corsWithPreflightResponse.

          -
          request's mode is "unsafe-no-cors" +
          request's mode is "user-agent-no-cors"
          1. Set request's response tainting to @@ -4832,7 +4832,7 @@ these steps:

          2. request's mode is not "no-cors" and response's type is "opaque" -

          3. request's mode is "unsafe-no-cors" +

          4. request's mode is "user-agent-no-cors"

          5. request's redirect mode is not "manual" and response's type is "opaqueredirect" @@ -5190,7 +5190,7 @@ run these steps: httpRequest's header list.
          -
        1. If either request's mode is not "unsafe-no-cors" +
        2. If either request's mode is not "user-agent-no-cors" or request's omit origin flag is not set,

          append a request `Origin` header for httpRequest.