Skip to content

Commit

Permalink
Merge pull request #13 from arichiv/extensions
Browse files Browse the repository at this point in the history
Add two new extension explainers
  • Loading branch information
arichiv authored Jan 17, 2024
2 parents 4dece5a + 1ce24f9 commit fd1815d
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 1 deletion.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Explainer: Extending Storage Access API (SAA) to non-cookie storage

[Discussion](https://github.com/arichiv/saa-non-cookie-storage/issues)
* [Discussion](https://github.com/arichiv/saa-non-cookie-storage/issues)
* [Additional Extension: Omit Unpartitioned Cookies](https://arichiv.github.io/saa-non-cookie-storage/omit-unpartitioned-cookies.html)
* [Additional Extension: Shared Workers](https://arichiv.github.io/saa-non-cookie-storage/shared-workers.html)

## Introduction

Expand Down
4 changes: 4 additions & 0 deletions idl.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
```
partial interface Document {
Promise<StorageAccessHandle> requestStorageAccess(StorageAccessTypes types);
Promise<boolean> hasUnpartitionedCookieAccess();
};
dictionary StorageAccessTypes {
boolean all = false;
boolean cookies = false;
boolean sessionStorage = false;
boolean localStorage = false;
boolean indexedDB = false;
Expand All @@ -15,6 +17,7 @@ dictionary StorageAccessTypes {
boolean createObjectURL = false;
boolean revokeObjectURL = false;
boolean BroadcastChannel = false;
boolean SharedWorker = false;
};
interface StorageAccessHandle {
Expand All @@ -28,4 +31,5 @@ interface StorageAccessHandle {
DOMString createObjectURL((Blob or MediaSource) obj);
undefined revokeObjectURL(DOMString url);
BroadcastChannel BroadcastChannel(DOMString name);
SharedWorker SharedWorker(USVString scriptURL, optional (DOMString or WorkerOptions) options = {});
};
69 changes: 69 additions & 0 deletions omit-unpartitioned-cookies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Explainer: Extending Storage Access API (SAA) to omit unpartitioned cookies

* [Discussion](https://github.com/arichiv/saa-non-cookie-storage/issues)

# Introduction

This extension to “[Explainer: Extending Storage Access API (SAA) to non-cookie storage](https://arichiv.github.io/saa-non-cookie-storage/)” proposes adding a mechanism to not force unpartitioned cookie access when all that the developer needs is some other unpartitioned storage access via SAA. This is one of two proposed extensions going out together.

# Motivation

The current [Storage Access API](https://github.com/privacycg/storage-access) requires that unpartitioned cookie access is granted if any unpartitioned storage access is needed. This forces unpartitioned cookies to be included in network requests which may not need them, having impacts on network performance and security. Before the [extension](https://arichiv.github.io/saa-non-cookie-storage/) ships, we have a chance to fix this behavior without a compatibility break.

# Goals

1. Provide a way for developers to ensure continuity of user experience with unpartitioned storage access without forcing unpartitioned cookie access.
2. Improve the privacy and security properties of the Storage Access API (largely lauded by the web community), while providing more flexibility for developers.

# Non-Goals

1. Address all breakage resulting from storage partitioning:
1. Use cases intended for pervasive tracking of users is not in scope
1. Some anti-fraud use cases may need to be handled by a separate API, given the constraints of the SAA implementation
1. Push developers to migrate away from cookies to other storage mechanisms or vice-versa.

# Proposed Solution

We propose an extension of the [Storage Access API non-cookie extension](https://arichiv.github.io/saa-non-cookie-storage/) to provide a `cookies` argument which defines whether unpartitioned cookies will or won’t be included in future fetch requests. The API shape isn’t final, but for the sake of explanation and example it is treated as well defined below.

```javascript
// The following code would be run in a cross-site iframe for example.com.

// The following two lines would be functionally identical to support the existing no-argument version of `requestStorageAccess` which attaches unpartitioned cookies to future fetch requests.
await document.requestStorageAccess();
await document.requestStorageAccess({cookies: true});

// The following would attach unpartitioned cookies to future fetch requests.
let handle = await document.requestStorageAccess({all: true});

// The following would not attach unpartitioned cookies to future fetch requests.
let handle = await document.requestStorageAccess({sessionStorage: true});

// The following would attach unpartitioned cookies to future fetch requests.
let handle = await document.requestStorageAccess({sessionStorage: true, cookies: true});

// The following would not attach unpartitioned cookies to future fetch requests.
let handle = await document.requestStorageAccess({sessionStorage: true, cookies: false});

// The following (and any other request where all fields are false or missing) would be rejected due to nothing being requested.
await document.requestStorageAccess({});
await document.requestStorageAccess({all: false});
```

Note that once cookies are attached to future fetch requests this will remain true for the lifetime of the iframe. Calling `requestStorageAccess` again with different arguments would not change that.

Further, we propose defining a new async function `hasUnpartitionedCookieAccess` which returns true if unpartitioned cookies have been attached to future fetch requests and false otherwise. `hasStorageAccess` should be considered for future deprecation as it serves the same purpose but with a less clear name. The purpose of this is to ensure developers know this is a way to check if unpartitioned cookies had been attached, whereas the current naming implies it returns true if `requestStorageAccess` has ever been successfully called for any reason.

## Prompting the User

Browsers currently shipping the Storage Access API apply varying methods of when or how to ask the user for permission to grant 3p cookie access to a site. Given that this proposal involves extending the existing Storage Access API, while maintaining largely the same implications (from a privacy/security perspective) to the user, a consistent prompt for cookie and non-cookie access is preferred.

# Alternatives & Questions

## omitCookies param

We could instead offer an `omitCookies` param which defaults false but could be set to true to prevent future fetch requests from attaching unpartitioned cookies. If possible, passing a boolean to cause something not to happen should be avoided in favor of passing a boolean to cause something to happen. The one wrinkle here is the need to support the legacy case of calling `requestStorageAccess` with no arguments, but treating that as unique from the case where `requestStorageAccess` is called with an argument seems reasonable for legacy support.

# Privacy & Security Considerations

In extending an existing access-granting API, care must be taken not to open additional security issues or abuse vectors relative to comprehensive cross-site cookie blocking and storage partitioning. This extension offers only a way to limit privacy and security abuse, and no new vector for exploitation.
102 changes: 102 additions & 0 deletions shared-workers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Explainer: Extending Storage Access API (SAA) to Shared Workers

* [Discussion](https://github.com/arichiv/saa-non-cookie-storage/issues)

# Introduction

This extension to “[Explainer: Extending Storage Access API (SAA) to non-cookie storage](https://arichiv.github.io/saa-non-cookie-storage/)” proposes adding Shared Workers to the SAA handle. This is one of two proposed extensions going out together.

# Motivation

There has been increasing [developer](https://github.com/GoogleChromeLabs/privacy-sandbox-dev-support/issues/124) and [implementer](https://github.com/privacycg/storage-access/issues/157) interest in first-party workers being available in third-party contexts the same way that [third-party cookies already can be](https://github.com/privacycg/storage-access). In the absence of such a solution, we leave developers without a robust way to manage cross-tab state for frames loading the same origin. This explainer proposes a solution for developers to regain third-party access to Shared Workers in select instances to avoid user-facing breakage in browsers shipping storage partitioning.

# Goals

1. Provide a way for developers to ensure continuity of user experience with unpartitioned third-party Shared Workers, without enabling pervasive tracking of users.
1. Maintain the privacy and security properties of the Storage Access API , while providing more flexibility for developers.
1. Avoid pushing developers to migrate to different worker and storage mechanisms, especially when there are privacy/security/performance reasons to support one implementation over another in specific scenarios.

# Non-Goals

1. Address all breakage resulting from storage partitioning:
1. Use cases intended for pervasive tracking of users is not in scope
1. Some anti-fraud use cases may need to be handled by a separate API, given the constraints of the SAA implementation
1. Provide a passive mechanism to access first-party workers in third-party contexts.

# Use Cases

## [Maintaining a Session](https://github.com/GoogleChromeLabs/privacy-sandbox-dev-support/issues/124)

A developer embeds chat.com on two of their sites site-a.com and site-b.com. chat.com uses Shared Workers to maintain a user session.

## [Transfering an ArrayBuffer](https://groups.google.com/a/chromium.org/g/blink-dev/c/inRN8tI49O0/m/Q_TE0cw4AAAJ)

A developer embeds worker.com on two of their sites site-a.com and site-b.com. worker.com uses Shared Workers to transfer ArrayBuffers via postMessage.

# Proposed Solution

We propose adding a new [option to the SharedWorker constructor](https://html.spec.whatwg.org/dev/workers.html#shared-workers-and-the-sharedworker-interface) that controls whether cookies with SameSite=Lax/Strict are included so that these sensitive cookies aren’t included in contexts where they aren’t required. This option could be called `sameSiteCookies`, which could accept one of two values: ‘all’ or ‘none’ (the name isn’t finalized, but for the sake of the examples and explanation we will use these for now). The default value, when the option isn’t set, would be the same as setting ‘all’ in a top-level frame and the same as setting ‘none’ in any other frame. The only real customization this permits is the ability to set ‘none’ where the default would be ‘all’; setting ‘all’ where the default is ‘none’ is not permitted as such a context would lack access to SameSite Strict/Lax cookies.

```javascript
// The following code would be run in a top-level frame for example.com.

// This would start a first-party Shared Worker with the same behavior as before.
const sharedWorker1 = new SharedWorker("shared_worker.js");

// This would reference the same worker as `sharedWorker1`.
const sharedWorker2 = new SharedWorker("shared_worker.js", {sameSiteCookies: 'all'});

// This is a new Shared Worker that lacks lax/strict cookie access.
const sharedWorker3 = new SharedWorker("shared_worker.js", {sameSiteCookies: 'none'});
```

We further propose an extension of the [Storage Access API non-cookie extension](https://arichiv.github.io/saa-non-cookie-storage/) to provide a way to create Shared Workers that have access to first-party storage.

```javascript
// The following code would be run in a cross-site iframe for example.com.

// This would start a third-party Shared Worker with the same behavior as before.
const sharedWorker4 = new SharedWorker("shared_worker.js");

// This would reference the same worker as `sharedWorker4`.
const sharedWorker5 = new SharedWorker("shared_worker.js", {sameSiteCookies: 'none'});

// This would throw a DOM security exception.
new SharedWorker("shared_worker.js", {sameSiteCookies: 'all'});

// Request a new storage handle via rSA (this should prompt the user)
let handle = await document.requestStorageAccess({all: true});

// This worker has first-party storage acccess but lacks strict and lax cookies. It would reference the same worker as `sharedWorker3`.
const sharedWorker6 = handle.SharedWorker("shared_worker.js");

// This would reference the same worker as `sharedWorker3`.
const sharedWorker7 = handle.SharedWorker("shared_worker.js", {sameSiteCookies: 'none'});

// This would throw a DOM security exception.
handle.SharedWorker("shared_worker.js", {sameSiteCookies: 'all'});
```

If the argument `{all: true}` is provided all available storage/communication mechanisms will be prepared and attached to the handle. Otherwise, a site could request just specific mechanisms like shared workers with `{SharedWorker: true}`. This flexibility is provided to ensure developers can avoid any performance impact from loading unused storage/communication mechanisms.

## Prompting the User

Browsers currently shipping the Storage Access API apply varying methods of when or how to ask the user for permission to grant third-party cookie access to a site. Given that this proposal involves extending the existing Storage Access API, while maintaining largely the same implications (from a privacy/security perspective) to the user, re-using a consistent prompt for worker and non-worker access that any call to requestStorageAccess can trigger is preferred.

# Alternatives & Questions

## Service Workers

Service workers have [cache-based history sniffing attacks](https://www.ndss-symposium.org/wp-content/uploads/ndss2021_1C-2_23104_paper.pdf). Extending cross-site unpartitioned storage access to service workers would open up increased vulnerabilities and be somewhat confusing due to the way FetchEvent and other background events are not tied to an endpoint, thus first-party Service Workers will not be exposed in third-party contexts after an rSA call.

## Dedicated Worker support

We could support the same `hasSameSiteCookiesAccess` option for dedicated workers and make them constructable off of the SAA handle, but without a specific developer request this can be tabled for the time being.

## Worker-access to requestStorageAccess

We could expose `requestStorageAccess` within Dedicated or Shared Workers, and depend on the contexts that create or have access to the worker for knowing if the request should be granted. This on its own would not satisfy the use cases we must consider, as it would not provide a way to access the same shared worker in a first-party and third-party context. We may want to add such a feature in the future in an independent extension of SAA depending on developer demand.

# Privacy & Security Considerations

In extending an existing access-granting API, care must be taken not to open additional security issues or abuse vectors relative to comprehensive cross-site cookie blocking and storage partitioning. Except for Service Workers (which will not be supported in this extension) we believe shared worker access can be provided as long as `SameSite=Strict` and `SameSite=Lax` cookies are not read or written in these contexts. This limitation should provide the same privacy and security guarantees already secured in the existing SAA access to cookies. The existing requestStorageAccess function provides access to unpartitioned cookies except those marked Strict or Lax, and this new extension will mirror that limitation in the new Shared Worker pool.

0 comments on commit fd1815d

Please sign in to comment.