1. Introduction
This section is non-normative.
Many User Agents prevent content from accessing non-same site data stored in cookies. This can break embedded content which relies on having access to non-same site cookies.
The requestStorageAccessFor API enables developers to request access to non-same site cookies for embedded resources such as iframes, scripts, or images.
It accomplishes this by specifying requestStorageAccessFor(requestedOrigin)
, which allows traversable navigables to request access
to unpartitioned cookies on behalf of another origin.
2. Infrastructure
This specification depends on the Infra standard. [INFRA]
3. The requestStorageAccessFor API
This specification defines a method that can be used to request access to unpartitioned data on behalf of another origin (requestStorageAccessFor(requestedOrigin)
).
Alex visits https://social.example/
. The page sets a cookie. This cookie has been set in a first-party-site context.
Later on, Alex visits https://video.example/
, which has an img
in it which loads https://social.example/profile-image
. In this case, the social.example
Document
doc is in a third party context, and the cookie set previously might or might not be visible from doc.
cookie
, depending on User Agent storage access policies.
A script on https://video.example/
could request access on behalf of https://social.example
by calling doc.
requestStorageAccessFor(requestedOrigin)
with USVString
requestedOrigin as https://social.example
.
Note: the circumstances for use of the access have to be limited to those cases where the requested origin opts into sharing. More information is available in § 7 Privacy considerations and § 8 Security considerations.
Unpartitioned data is client-side storage that would be available to a site were it loaded in a first-party-site context.
A Document
is in a first-party-site context if it is the active document of a traversable navigable. Otherwise, it is in a first-party-site context if it is an active document and the origin and top-level origin of its relevant settings object are same site with one another.
A Document
is in a third party context if it is not in a first-party-site context.
3.1. Changes to Document
partial interface Document {Promise <undefined >requestStorageAccessFor (USVString ); };
requestedOrigin
Document
doc with USVString
requestedOrigin, the requestStorageAccessFor(requestedOrigin)
method must run these steps:
-
Let p be a new promise.
-
If doc is not fully active, then reject p with an "
InvalidStateError
"DOMException
and return p. -
If doc’s node navigable is not a traversable navigable, reject p with an "
NotAllowedError
"DOMException
and return p. -
If doc’s origin is an opaque origin, reject p with an "
NotAllowedError
"DOMException
and return p. -
If doc’s relevant global object is not a secure context, then reject p with a "
NotAllowedError
"DOMException
and return p. -
Let parsedURL be the the result of running the URL parser on requestedOrigin.
-
If parsedURL is failure, reject p with a
TypeError
and return p. -
Let origin be parsedURL’s origin.
-
If origin is an opaque origin, reject p with an "
NotAllowedError
"DOMException
and return p. -
If doc’s origin is same origin with origin, resolve and return p.
-
Let descriptor be a newly created
TopLevelStorageAccessPermissionDescriptor
withname
set to "top-level-storage-access
" and withrequestedOrigin
set to origin. -
Let has activation be true if doc’s
Window
object has transient activation, and false otherwise. -
Run these steps in parallel:
-
Let settings be doc’s relevant settings object.
-
Let global be doc’s relevant global object.
-
Let existing state be descriptor’s permission state with settings.
-
If existing state is granted:
-
Queue a global task on the permissions task source given global to resolve p.
-
Return.
-
-
If existing state is denied:
-
If doc’s
Window
object has transient activation, consume user activation with it. -
Queue a global task on the permissions task source given global to reject p with a "
NotAllowedError
"DOMException
. -
Return.
-
-
Assert that doc’s node navigable is a traversable navigable.
-
If has activation is false:
-
Queue a global task on the permissions task source given global to reject p with a n "
NotAllowedError
"DOMException
. -
Return.
-
-
Let permissionState be the result of requesting permission to use "
top-level-storage-access
" with descriptor.NOTE: Note that when requesting permissions and deciding whether to show a prompt, user agents apply implementation-defined behavior to shape the end user experience. Particularly for
top-level-storage-access
, user agents are known to apply custom rules that will grant or deny a permission without showing a prompt. -
If permissionState is granted:
-
Queue a global task on the permissions task source given global to resolve p.
-
Return.
-
-
If doc’s
Window
object has transient activation, consume user activation with it. -
Queue a global task on the permissions task source given global to reject p with a "
NotAllowedError
"DOMException
.
-
-
Return p.
The permissions task source shouldn’t be used directly. [Issue #privacycg/requestStorageAccessFor#15]
3.2. User Agent top-level storage access policies
-
Let settings be request’s client's relevant global object's relevant settings object.
-
Let descriptor be a newly created
TopLevelStorageAccessPermissionDescriptor
withname
set to "top-level-storage-access
" and withrequestedOrigin
set to embedded origin. -
Let existing state be descriptor’s permission state with settings.
-
If existing state is granted, return true.
-
Return false.
4. Permissions Integration
The requestStorageAccessFor API defines a powerful feature identified by the name "top-level-storage-access
". It defines the following permission-related algorithms:
PermissionDescriptor
-
The "
top-level-storage-access
" powerful feature defines aPermissionDescriptor
as follows:dictionary
:TopLevelStorageAccessPermissionDescriptor PermissionDescriptor {USVString
= ""; };requestedOrigin - permission query algorithm
-
To query the "
top-level-storage-access
" permission, given aPermissionDescriptor
permissionDesc and aPermissionStatus
status, run the following steps:-
Set status’s
state
to permissionDesc’s permission state. -
If status’s
state
is denied, set status’sstate
to prompt.Note: The denied permission state is not revealed to avoid exposing the user’s decision to developers. This is done to prevent retaliation against the user and repeated prompting to the detriment of the user experience.
-
- permission key type
-
A permission key of the "
top-level-storage-access
" feature has the type site.Note: the
requestedOrigin
field ensures that the permission store entry is double-keyed. - permission key generation algorithm
-
To generate a new permission key for the "
top-level-storage-access
" feature, given an environment settings object settings, run the following steps:-
Let current origin be settings’ origin.
-
If current origin is not same site with settings’ top-level origin, return null.
-
Return the result of obtaining a site from settings’ top-level origin.
Note: the check for whether settings’ origin is same site with settings’ top-level origin is intended to disallow permission queries from cross-site frames. This depends on the invariant that
top-level-storage-access
permission requests are only allowed in a top-level browsing context. As such, this check is only relevant inquery(permissionDesc)
.
-
- permission key comparison algorithm
-
To compare permission keys key1 and key2 for the "
top-level-storage-access
" feature, run the following steps:-
If key1 is null or key2 is null, return false.
-
Return key1 is same site with key2.
-
5. Fetch Integration
The requestStorageAccessFor(requestedOrigin)
only directly affects cookie behavior on subresource requests made from top-level documents to the requested origin.
-
Let has top-level access be the result of running determine if a request has top-level storage access on request.
-
If has top-level access is false, return false.
-
Let is subresource be true if request is a subresource request and false otherwise.
-
Let allowed subresource mode be true if request’s mode is "cors" and request’s credentials mode is "include", and false otherwise.
-
If is subresource is true and allowed subresource mode is false, return false.
-
If request’s client's relevant global object's associated document is not a traversable navigable, return false.
-
Return true.
6. Storage Access API Integration
Note: even after a successful requestStorageAccessFor(requestedOrigin)
call, frames have to explicitly invoke requestStorageAccess()
for cookie access.
This modification allows requestStorageAccessFor(requestedOrigin)
to allow resolution of requestStorageAccess()
calls similarly to a prior successful requestStorageAccess()
grant.
requestStorageAccess()
to insert the following steps before step 13.4 (i.e. before checking transient activation):
-
Let settings be doc’s relevant settings object.
-
Let origin be settings’ origin.
-
Let descriptor be a newly created
TopLevelStorageAccessPermissionDescriptor
withname
set to "top-level-storage-access
" and withrequestedOrigin
set to origin. -
If descriptor’s permission state is granted, queue a global task on the permissions task source given global to resolve p, and return.
-
If descriptor’s permission state is denied, queue a global task on the permissions task source given global to reject p with a "
NotAllowedError
"DOMException
, and return.
7. Privacy considerations
Like the [STORAGE-ACCESS], requestStorageAccessFor(requestedOrigin)
is intended to enable removal of cross-site cookies. It enables developers to re-gain cross-site cookies with additional constraints.
Note: many of the same considerations as in The Storage Access API § 6 Privacy considerations apply. This section primarily covers the differences.
requestStorageAccess()
requires interaction with an embedded document. By requiring interaction only with the top-level document, requestStorageAccessFor(requestedOrigin)
lowers the bar for a potential prompt, though embedded documents can also be quite prominent (or use other techniques to get user interaction). Implementation-defined acceptance and rejection steps are intended to allow user agents to reject abusive requests based on logic they see fit.
The prompts used have to be careful to indicate the direction of the request, such that the user is able to understand who is requesting access.
As with requestStorageAccess()
, the same tension between user consent and prompt fatigue exists with requestStorageAccessFor(requestedOrigin)
; much like the Storage Access API, implementation-defined acceptance and rejection steps are intended to enable implementers with differing stances on this question to make compromises as they see fit.
Another difference is that queries for the permission can be more sensitive, depending on the context. Note that a frame has to be unable to request the state of either of:
-
Whether it was granted a "
top-level-storage-access
" permission for some origin while a top-level document. -
Whether arbitrary other origins were granted the "
top-level-storage-access
" on the current top-level site.
In the former case, this would allow bogus domains (or combinations thereof) to be used as identifiers; in the latter case, it would reveal state under unrelated origins.
8. Security considerations
It is important that requestStorageAccessFor(requestedOrigin)
not degrade security properties of the web platform, even when compared to post-removal of cross-site cookies.
Third-party cookie removal has potential benefits for security, specifically in mitigating attacks that rely upon authenticated requests, e.g. CSRF.
We do not wish requestStorageAccessFor(requestedOrigin)
to be a foothold for such attacks to leverage.
Note: The Storage Access API § 7 Security considerations properties hold for much of this proposal. Specifically, frame-level access is only granted once requestStorageAccess()
is successfully invoked.
For frame access, requestStorageAccessFor(requestedOrigin)
merely simplifies the activation and prompting requirements.
requestStorageAccessFor(requestedOrigin)
does expand the scope of concerns in two areas: subresource requests made by the top-level document and potential notification abuse.
8.1. Subresource Requests
The specific security controls proposed by the API are:
-
Any cookies included with the subresource request have to be explicitly marked
SameSite=None
, indicating intent for use in third party contexts. -
For any
SameSite=None
cookies to be included, the request’s mode has to be "cors", where reading of the response is blocked unless the embeddee opts-in via sending the appropriate `access-control-allow-credentials
` header. The sending of the `origin
` header ensures the embeddee is aware of the embedder’s identity.
Additionally, only requests initiated from the top-level document will be eligible for inclusion of SameSite=None
cookies. This ensures that other embedded frames do not receive escalated privileges.
8.2. Notification Abuse
Unlike the [STORAGE-ACCESS], interaction is only required with the top-level document, rather than an embedded document. This does increase the likelihood of prompting.
Like the Storage Access API, user activation is consumed on denial, which prevents repeated requests.
The implementation-defined rejection steps also allow for imposition of numeric limits or denylists for abusive actors.
As mentioned in § 7 Privacy considerations, because of the direction of the request, the language in user agents' prompts should indicate which site initiated the storage access request.