[whatwg/fetch] Proposal: Allow servers to take full responsibility for cross-origin access protection (#878)

**TL;DR: Servers that explicitly take full control of cross-origin access protection, do not want the browser to handle this. Unfortunately, fully and indefinitely opting out is currently impossible.**

## Problem description

**By default, browsers are responsible for protecting cross-origin access to resources.** This mechanism was created to avoid that scripts running on one origin have undesired access to personalized content on on another origin.

**Currently, there is no _sustainable_ way for a server to take full responsibility of cross-origin access protection.** Servers can selectively opt out of blocking behavior, but no opt-out mechanism is guaranteed to work for all current _and_ future applications. As an example, we recently witnessed breakage of several legitimate applications that relied on a widely used server-side configuration from [enable-cors.org](https://enable-cors.org/), because the fetch specification had changed in subtle ways. The only resort is reconfiguring all servers, without guarantee that this will be a permanent solution.

While useful as a default, **the browser’s exclusive and changing control of cross-origin access forms an undesired obstacle in two common groups of scenarios:**

1. when the server **does not provide any personalization** for a resource (_“open data”_ or _“public APIs”_);

2. when a resource’s **personalized behavior is secured through other means** such as API keys or authentication headers set by the requesting script _(“authenticated APIs”)_.

## Use cases
#### (1) A **Web server does not provide any personalization** of certain resources, and wants to make those available to any Web application, now and forever.
Requirements:
- The server must be able to indicate that it wants to take full control of cross-origin access protection
- The server must be able to state this in a future-proof way
- The server must be able to state this for specific resources
- The server must be able to receive and send any headers, requests, and responses allowed by the HTTP specification, for those specific resources, from and to any origin
- The server must be able to not positively respond to requests whenever it so prefers
- The server must not need to be reconfigured when the fetch specification is updated

#### (2) A Web server **has its own cross-origin authorization mechanism** for certain resources, and wants to make those available to any Web application, now and forever.
Requirements:
- The server must be able to indicate that it wants to take full control of cross-origin access protection
- The server must be able to state this in a future-proof way
- The server must be able to state this for specific resources
- The server must be able to receive and send any headers, requests, and responses allowed by the HTTP specification, for those specific resources, from and to any origin
- The server must be able to not positively respond to requests whenever it so prefers
- The server must not need to be reconfigured when the fetch specification is updated

#### (3) A **Web application that makes cross-origin requests to public resources** on a certain server wants to keep working, now and forever (given no changes on the server).
Requirements:
- The application must be able to set any headers on the request
- The application must be able to read any response sent by the server
- The application’s ability to do the above must not change over time

#### (4) A **Web application that makes authenticated cross-origin requests** to resources on a certain server wants to keep working, now and forever (given no changes on the server).
Requirements:
- The application must be able to set any headers on the request
- The application must be able to read any response sent by the server
- The application’s ability to do the above must not change over time

#### (5) A **browser wants to move the responsibility for granting access to cross-origin resources** to the server when requested.
Requirements:
- The browser must be able to send a cross-origin request to the server unconditionally, when the server indicates that it takes full responsibility for cross-origin protection on that resource
- The browser’s ability to do the above must not change over time

#### (6) A **browser wants to maintain its possibility to provide granular cross-origin access protection** to servers that do not explicitly opt out of this protection
Requirements:
- Existing browser-based cross-origin protections must still work
- Existing granular CORS mechanisms must still work

#### (7) A **server developer wants a dedicated mechanism for taking server-side responsibility of cross-origin access control**
Requirements:
- The developer must understand what the mechanism does, and what responsibilities come with it
- The developer must not rely on mechanisms that have a related, but more granular meaning
- The developer must not abuse existing mechanisms to achieve this effect
- The developer must be able to do this in a way that does not change over time

#### (8) A **developer website** (such as [enable-cors.org](https://enable-cors.org/) or [developer.mozilla.org](https://developer.mozilla.org/)) wants to **document a future-proof way of taking server-side responsibility of cross-origin access protection**.
Requirements:
- These instructions must not change over time, or when the fetch specification is updated


## Shortcomings of current mechanisms
Currently, when trying to address the above use cases, servers must resort to multiple HTTP header settings that **eliminate cross-origin request blocking** by enabling **Cross-Origin Resource Sharing (CORS)**. In contrast, their actual goal is to request full responsibility for this protection. Therefore, the fact that only fine-grained settings are available is problematic, because:

1. It is **_complex_ to indicate that a server requests responsibility for all _current_ cross-origin requests**, as this configuration involves an interplay of several HTTP headers with subtle edge cases.

2. It is **_impossible) to indicate that a server requests responsibility for all _future_ cross-origin requests**, because of continuing changes to the fetch specification that tighten the mechanism. As such, legitimate Web applications relying on CORS can break at any time.

One could argue that this complexity and progressive tightening are beneficial for the protection of the server. However, this proposal argues for those **common cases where the server wants to take that protection in its own hands: public data, open APIs, authenticated APIs**.

Recent changes in the fetch specification broke widely deployed instructions such as those described on enable-cors.org. For instance, Web applications using HTTP requests with long headers suddenly stopped working in 2018/2019 after browser updates, even though their servers followed the enable-cors.org instructions with the explicit intention of this not happening. Fixing those applications requires changes on the server side. **Getting all affected Web servers updated is expensive** and will likely take several years, and there is **no guarantee that such an update will not be obsoleted again**. It is unsure whether troubled servers will be updated timely or at all, because blocked requests do not end up in server logs, so **servers have no way of knowing that applications have trouble accessing their resources**.

Concretely, we argue that a considerable number of servers emitting the `Access-Control-Allow-Origin: *` header actually **aim to express their wish to take control of cross-origin request protection themselves, and thus for the browser to fully delegate that responsibility**, instead of the much more nuanced and limited meaning this header actually has. These servers thus need a proper way of expressing this, without having to rely on the misinterpretation of an existing header.

## Current Web applications
The following Web applications seemingly have the intention of requesting full server-side control of cross-origin access protection. Instead, they resort to workarounds which, as argued above, can break at any point (and, in multiple cases, are currently broken):

- The Mapbox API: https://docs.mapbox.com/api/?language=JavaScript

- The Github API: https://developer.github.com/v3/#cross-origin-resource-sharing 
- OpenDataSoft’s product explicitly publishes datasets allowing all origins for their clients: `curl 'https://data.opendatasoft.com/api/records/1.0/search/?dataset=gare-de-train-et-tramway%40sarthe&facet=nom&facet=ligne&facet=typ_gare' -I`
- The Solid project by Tim Berners-Lee https://solid.github.io/web-access-control-spec/Background#cross-origin-resource-sharing-cors 
- All open data servers
  - data.gov
  - https://www.geonames.org/

  - See more at https://www.w3.org/wiki/CORS_Enabled

- public APIs
  - many of the APIs at https://github.com/toddmotto/public-apis

- dozens of additional examples available on request

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/fetch/issues/878

Received on Friday, 8 March 2019 15:30:06 UTC