1. Introduction
This section is non-normative.
User
Agents
sometimes
prevent
content
inside
certain
iframe
s
from
accessing
data
stored
in
client-side
storage
mechanisms
like
cookies.
This
can
break
embedded
content
which
relies
on
having
access
to
client-side
storage.
The
Storage
Access
API
enables
content
inside
iframe
s
to
request
and
be
granted
access
to
their
client-side
storage,
so
that
embedded
content
which
relies
on
having
access
to
client-side
storage
can
work
in
such
User
Agents.
[STORAGE-ACCESS-INTRO]
2. Infrastructure
This specification depends on the Infra standard. [INFRA]
3. The Storage Access API
This
specification
defines
a
method
to
query
whether
or
not
a
Document
currently
has
access
to
its
unpartitioned
data
(
hasStorageAccess()
),
and
a
method
that
can
be
used
to
request
access
to
its
unpartitioned
data
(
requestStorageAccess()
).
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
iframe
on
it
which
loads
https://social.example/heart-button
.
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.
Script
in
the
iframe
can
call
doc
.
hasStorageAccess()
to
determine
if
it
has
access
to
the
cookie.
If
it
does
not
have
access,
it
can
request
access
by
calling
doc
.
requestStorageAccess()
.
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
top-level
browsing
context
.
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
.
To
determine
whether
the
user
agent
explicitly
allows
unpartitioned
cookie
access
,
given
a
tuple
tuple
consisting
of
two
sites
,
run
the
following
steps.
This
algorithm
returns
"
none
",
"
allow
"
or
"
disallow
".
Note: A user agent’s settings might explicitly allow or disallow unpartitioned cookie access through per-site allow-lists, the user changing global browser settings, or similar custom overrides.
-
If the user agent does not have explicit settings for unpartitioned cookie access for tuple , return "
none". -
If the user agent’s settings explicitly allow unpartitioned cookie access for tuple , return "
allow". -
Assert : the user agent’s settings explicitly disallow unpartitioned cookie access for tuple .
-
Return "
disallow".
To determine the FedCM site connection status given a origin embedder and origin identityProvider , run the following steps. This algorithm returns a boolean .
-
For each item of connected accounts set :
-
Return false.
To
determine
the
effective
FedCM
connection
status
given
a
origin
embedder
,
a
origin
identityProvider
,
a
Document
doc
,
run
the
following
steps.
This
algorithm
returns
a
boolean
.
-
Let policyStatus be whether doc is allowed to use "
identity-credentials-get". -
If policyStatus is "Disabled", return false.
-
Let connected be the result of determining the site connection status given embedder and identityProvider .
-
If connected is false, return false.
-
Let preventSilentAccess be user agent ’s credential store ’s prevent silent access flag for embedder .
-
If preventSilentAccess , return false.
-
Return true.
3.1. Changes to user agent state related to storage access
Modify
the
definition
of
environment
in
the
following
manner:
Add
a
new
member
called
has
storage
access
of
type
boolean
.
Modify
the
definition
of
source
snapshot
params
in
the
following
manner:
-
Add a new member called has storage access of type boolean .
-
Add a new member called environment id of type opaque string .
A storage access eligibility is one of " unset ", " ineligible ", or " eligible ".
A
request
has
a
storage
access
eligibility
eligible
for
storage-access
.
It
is
initially
"
unset
".
Note:
a
request
’s
storage
access
eligibility
indicates
whether
previously-granted
"
storage-access
"
permissions
ought
to
be
considered
when
evaluating
which
cookies
to
include
on
the
request
.
In
particular,
note
that
after
requestStorageAccess
has
resolved
and
the
environment
’s
has
storage
access
is
set
to
true,
not
all
of
the
request
s
issued
by
that
environment
ought
to
carry
unpartitioned
cookies.
For
example,
suppose
the
user
is
visiting
a
page
on
https://top.com
which
embeds
an
iframe
served
from
https://embed.com,
and
a
script
in
that
iframe
has
called
requestStorageAccess
and
the
promise
resolved.
If
the
iframe
subsequently
fetches
a
resource
from
https://3p.com,
that
request
will
not
include
cookies
via
the
Storage
Access
API.
The concept of "ancestry" is being added to HTML in https://github.com/whatwg/html/pull/11133
-
If request ’s client ’s has storage access is false, return "
ineligible". -
If request ’s origin is not same origin with request ’s url ’s origin , return "
ineligible". -
Let allowed be the result of running Should request be allowed to use feature? given "
storage-access" and request . -
If allowed is false, return "
ineligible". -
Return "
eligible".
3.2.
Changes
to
Document
partial interface Document {Promise <boolean >hasStorageAccess ();Promise <undefined >requestStorageAccess (); };
When
invoked
on
Document
doc
,
the
hasStorageAccess()
method
must
run
these
steps:
-
Let p be a new promise .
-
If doc is not fully active , then reject p with an "
InvalidStateError"DOMExceptionand return p . -
If doc ’s origin is an opaque origin , resolve p with false and return p .
-
Let global be doc ’s relevant global object .
-
If global is not a secure context , then resolve p with false and return p .
-
If the top-level origin of doc ’s relevant settings object is an opaque origin , resolve p with false and return p .
-
Let browsingContext be doc ’s browsing context .
-
Let topLevelSite be the result of obtaining a site from the top-level origin of doc ’s relevant settings object .
-
Let embeddedSite be the result of obtaining a site from doc ’s origin .
-
Run the following steps in parallel :
-
Let explicitSetting be the result of determining whether the user agent explicitly allows unpartitioned cookie access with ( topLevelSite , embeddedSite ).
-
Let permissionState be the result of getting the current permission state given "
storage-access" and global . -
Queue a global task on the networking task source given global to:
-
If explicitSetting is "
disallow", resolve p with false. -
If explicitSetting is "
allow", resolve p with true. -
Assert : explicitSetting is "
none". -
If browsingContext is a top-level browsing context , resolve p with true.
-
If browsingContext is same authority with browsingContext ’s top-level browsing context ’s active document , resolve p with true.
"same authority" here is a placeholder for a future concept that allows user agents to perform same site checks while adhering to additional security aspects such as the presence of a cross-site parent document, see whatwg/storage#142 . In practice, this might involve comparing the site for cookies or performing a same site check with the top-level document.
-
If permissionState is granted , resolve p with global ’s has storage access .
Note: The global storage access permission state takes precedence over the local has storage access flag here, in order to immediately reflect a possible user choice to revoke the permission in their settings.
-
Resolve p with false.
-
-
-
Return p .
When
invoked
on
Document
doc
,
the
requestStorageAccess()
method
must
run
these
steps:
-
Let p be a new promise .
-
If doc is not fully active , then reject p with an "
InvalidStateError"DOMExceptionand return p . -
Let global be doc ’s relevant global object .
-
Let settings be doc ’s relevant settings object .
-
If global is not a secure context , then reject p with a "
NotAllowedError"DOMExceptionand return p . -
If doc is not allowed to use "
storage-access", reject p with a "NotAllowedError"DOMExceptionand return p . -
If doc ’s origin is an opaque origin , reject p with a "
NotAllowedError"DOMExceptionand return p . -
If settings ’s top-level origin is an opaque origin , reject p with a "
NotAllowedError"DOMExceptionand return p . -
If doc ’s active sandboxing flag set has its sandbox storage access by user activation flag set, reject p with a "
NotAllowedError"DOMExceptionand return p . -
Let browsingContext be doc ’s browsing context .
-
Let topLevelOrigin be the top-level origin of doc ’s relevant settings object .
-
Let topLevelSite be the result of obtaining a site from topLevelOrigin .
-
Let embeddedOrigin be doc ’s origin .
-
Let embeddedSite be the result of obtaining a site from embeddedOrigin .
-
Let has transient activation be whether doc ’s
Windowobject has transient activation . -
Run the following steps in parallel :
-
Let process permission state be an algorithm that, given a permission state state , runs the following steps:
-
Queue a global task on the networking task source given global to:
-
If state is granted :
-
Set global ’s has storage access to true.
-
-
Else:
-
Consume user activation given global .
-
Reject p with a "
NotAllowedError"DOMException.
-
-
-
-
Let explicitSetting be the result of determining whether the user agent explicitly allows unpartitioned cookie access with ( topLevelSite , embeddedSite ).
-
If explicitSetting is "
disallow":-
Run process permission state with denied .
-
Abort these steps.
-
-
If explicitSetting is "
allow":-
Run process permission state with granted .
-
Abort these steps.
-
-
Assert : explicitSetting is "
none". -
If browsingContext is a top-level browsing context :
-
Run process permission state with granted .
-
Abort these steps.
-
-
If embeddedSite is same site with topLevelSite :
NOTE: This check is same site on purpose, to allow embedded sites to use
requestStorageAccess()to opt into storage access without involvement from the end user in scenarios where storage access is restricted for security and not privacy purposes.-
Run process permission state with granted .
-
Abort these steps.
-
-
Let previous permission state be the result of getting the current permission state given "
storage-access" and global . -
If previous permission state is not prompt :
-
Run process permission state with previous permission state .
-
Abort these steps.
-
-
Let connected be the result of determining the effective FedCM connection status given topLevelOrigin , embeddedOrigin , doc .
-
If connected :
NOTE: User agents are encouraged to keep track of which (site, site) tuples have been allowed to access storage due to existing FedCM connections, and double-check that list when accessing cookies to catch malicious attackers that have tricked an environment into using an incorrect has storage access bit.
-
Run process permission state with granted .
-
Abort these steps.
-
-
If has transient activation is false:
-
Run process permission state with denied .
-
Abort these steps.
-
-
Let permissionState be the result of requesting permission to use "
storage-access".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
storage-access, user agents are known to apply custom rules that will grant or deny a permission without showing a prompt. -
Run process permission state with permissionState .
-
-
Return p .
NOTE: The intent of this algorithm is to always require user activation before a storage-access permission will be set. Though it is within the means of user agents to set storage-access permissions based on custom heuristics without prior user activation, this specification strongly discourages such behavior, as it could lead to interoperability issues.
3.3. Changes to navigation
When snapshotting source snapshot params :
-
Set has storage access to sourceDocument ’s has storage access .
-
Set environment id to sourceDocument ’s relevant settings object ’s id .
To the create navigation params by fetching algorithm, insert the following step as step 3:
-
Let originalURL be entry ’s URL.
When creating request ’s reserved client in create navigation params by fetching :
-
Set reserved client ’s has storage access to sourceSnapshotParams ’s has storage access if all of the following hold:
-
sourceSnapshotParams ’s environment id equals navigable ’s active document ’s relevant settings object ’s id .
-
originalURL ’s origin is same origin with currentURL ’s origin .
-
response is null or response ’s has-cross-origin-redirects is false.
-
-
Otherwise, set request ’s reserved client ’s has storage access to false.
When setting up a window environment settings object :
-
Set settings object ’s has storage access to reserved environment ’s has storage access .
3.4. Integration with Fetch
3.4.1. Fetching
Insert a new step after step 14 of fetch :
-
Set request ’s eligible for storage-access to the result of determining the initial storage-access eligibility given request .
3.4.2. HTTP-redirect-fetch
Insert a new step after step 17 of HTTP-redirect fetch :
-
If request ’s eligible for storage-access is not "
unset" and locationURL ’s origin is not same origin with request ’s current URL ’s origin , set request ’s eligible for storage-access to "ineligible".
3.5. Changes to various client-side storage mechanisms
This API only impacts HTTP cookies. A future revision of this API might impact other client-side state. [RFC6265]
3.5.1. Cookies
This
API
is
intended
to
be
used
with
environments
and
user
agent
configurations
that
block
access
to
unpartitioned
cookies
in
a
third
party
context
.
At
the
time
of
this
writing,
this
concept
has
not
yet
been
integrated
into
the
HTTP-network-or-cache
fetch
and
cookie
algorithms.
To
allow
for
such
an
integration,
the
cookie
store
will
need
to
be
modified
to
receive
information
about
the
top-level
and
embedded
site
of
the
request
(to
determine
whether
to
attach
cross-site,
partitioned,
or
no
cookies)
as
well
as
whether
the
request
was
made
for
a
document
that
has
storage
access,
through
accessing
the
request
’s
eligible
for
storage-access
that
is
defined
in
this
specification.
Once
the
cookie
store
allows
for
receiving
information
about
storage
access,
we
would
update
HTTP-network-or-cache
fetch
and
cookie
to
pass
the
request
’s
eligible
for
storage-access
to
the
cookie
store
when
retrieving
cookies.
When
getting
unpartitioned
cookies
from
the
cookie
store
with
storage
access,
user
agents
will
still
follow
applicable
SameSite
restrictions
(i.e.,
not
attach
cookies
marked
SameSite=Strict
or
SameSite=Lax
in
third
party
contexts
).
Note:
User
agents
could
apply
different
default
values
for
the
SameSite
cookie
attribute.
This
could
lead
to
unpartitioned
cookies
without
a
SameSite
attribute
being
attached
to
requests
in
some
user
agents
(where
SameSite=None
is
the
default),
but
not
in
others
(where
SameSite=Lax
is
the
default).
Web
developers
are
encouraged
to
set
the
SameSite
attribute
on
their
cookies
to
not
run
into
issues.
3.6. Sandboxing storage access
A sandboxing flag set has a sandbox storage access by user activation flag . This flag prevents content from requesting storage access.
To the parse a sandboxing directive algorithm, add the following under step 3:
-
The
sandbox
storage
access
by
user
activation
flag
,
unless
tokens
contains
the
allow-storage-access-by-user-activationkeyword.
4. Permissions Integration
The
Storage
Access
API
defines
a
powerful
feature
identified
by
the
name
"
storage-access
".
It
defines
the
following
permission-related
algorithms:
- permission query algorithm
-
To
query
the
"
storage-access" permission, given aPermissionDescriptorpermissionDesc and aPermissionStatusstatus :-
Set status ’s
stateto permissionDesc ’s permission state . -
If status ’s
stateis denied , set status ’sstateto 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
"
storage-access" feature is a tuple consisting of a site top-level and a site requester .(("https", "news.example"), ("https", "social.example"))is a permission key for "storage-access" whose top-level is("https", "news.example")and whose requester is("https", "social.example"). - permission key generation algorithm
-
To
generate
a
new
permission
key
for
the
"
storage-access" feature, given an environment settings object settings , run the following steps:-
Let topLevelSite be the result of obtaining a site from settings ’ top-level origin .
-
Let embeddedSite be the result of obtaining a site from settings ’ origin .
-
Return ( topLevelSite , embeddedSite ).
-
- permission key comparison algorithm
-
To
compare
the
permission
keys
key1
and
key2
for
the
"
storage-access" feature, run the following steps:
5. Permissions Policy Integration
The
Storage
Access
API
defines
a
policy-controlled
feature
identified
by
the
string
"storage-access"
.
Its
default
allowlist
is
"*"
.
Note:
A
Document
’s
permissions
policy
determines
whether
any
content
in
that
document
is
allowed
to
request
storage
access
using
requestStorageAccess()
.
If
disabled
in
any
document,
calling
requestStorageAccess()
in
that
document
will
reject.
6. Privacy considerations
The Storage Access API enables the removal of cross-site cookies. Specifically, it allows the authenticated embeds use case to continue to work. As such, the API provides a way for developers to re-gain access to cross-site cookies, albeit under further constraints.
A
nested
Document
gains
access
to
the
same
cookies
it
has
as
the
active
document
of
a
top-level
browsing
context
when
it
calls
requestStorageAccess()
and
is
returned
a
resolving
Promise
.
With
these
cookies
it
can
authenticate
itself
to
the
server
and
load
user-specific
information.
While
this
functionality
comes
with
a
risk
of
abuse
by
third
parties
for
tracking
purposes,
it
is
an
explicit
goal
of
the
API
and
a
key
to
its
design
to
not
undermine
the
gains
of
cross-site
cookie
deprecation.
Importantly,
we
do
not
degrade
privacy
properties
when
compared
to
pre-removal
of
cross-site
cookies.
This
follows
from
a
lack
of
platform-specific
information
used
in
the
spec
to
prevent
stateless
tracking
and
the
only
state
added
being
a
permission
scoped
to
the
sites
of
the
embedding
and
embedded
Document
.
Our
privacy
considerations
are
more
challenging
where
default
cross-site
cookies
are
already
deprecated.
The
challenge
is
to
decide
when
and
how
to
permit
the
Storage
Access
API
to
be
used
to
revert
a
cookie-less
(or
cookie-partitioned)
nested
Document
to
a
pre-deprecation
state,
giving
it
access
to
its
unpartitioned
data
.
In
an
ideal
case,
a
nested
Document
would
only
be
able
to
gain
access
to
its
unpartitioned
data
if:
-
the user interacts with the nested
Document -
the nested
Documentis permitted by the embedder to use the API -
the nested
Documentis a secure context -
the user grants express, pairwise permission to the embeddee to use its cookies in the embedder
-
the user is not inundated by requests for the "
storage-access" permission so their express permission is not undermined by fatigue
This
specification
requires
the
first
three
of
implementers.
This
provides
guarantees
that
the
user
is
aware
of
the
content
of
the
nested
Document
,
the
embedder
has
not
opted
out
of
the
nested
Document
’s
authentication,
and
the
cross-site
cookies
are
not
disclosed
to
network
attackers,
respectively.
The
last
two
points
are
in
tension.
In
an
ideal
world,
we
would
show
a
prompt
to
the
user
in
every
call
to
requestStorageAccess()
.
But,
this
would
allow
pages
to
prompt
the
user
so
frequently
as
to
put
the
last
point
at
the
discretion
of
the
page–
a
state
we
find
unacceptable.
User
agents
should
prevent
over-prompting
of
the
user.
document.
requestStorageAccess()
.
Thus, the last two points represent a key point of compromise. We permit implementation-defined behavior on when to grant or deny requests for unpartitioned data without requiring user choice so long as they meet all other requirements. This compromise weakens the privacy guarantees of this proposal, specifically point 4, to a degree under the control of the implementer and gives the implementer the power to render it impossible to get storage access with this API. However, this has proven necessary to enable condition 5 to be possible given our implementers' differing stances on the compromise between these two points.
Developer experience suffers where user agents differ greatly in their implementation-defined behavior, and therefore user agents should aim to minimize or standardize silent grants and denies.
6.1. Permission scope
Another
tension
in
the
design
of
the
API
is
what
to
use
to
key
the
"
storage-access
"
permission:
origins
or
sites
.
We
chose
sites
because
we
believe
them
to
be
acceptable
boundaries
for
privacy
while
enabling
existing
uses
of
same
site
and
cross-origin
nested
Documents
on
the
same
page
with
only
one
user
prompt.
7. Security considerations
It is important that this spec 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 the Storage Access API to be a foothold for such attacks to leverage.
To
this
end,
we
limit
the
impact
of
a
"
storage-access
"
permission
grant
to
only
give
access
to
unpartitioned
data
to
the
nested
Document
that
called
requestStorageAccess()
and
only
until
the
nested
Document
navigates
across
an
origin
boundary.
This
ensures
that
only
origins
with
a
page
that
call
requestStorageAccess()
will
be
making
credentialed
requests,
and
moreover
the
embedee
page
can
control
which
embedder
it
permits
via
the
Content
Security
Policy
"
frame-ancestors
"
directive.
This
retains
an
origin
-scoped
control
for
security
purposes
by
the
embedee.
7.1. Reputational attacks
This also is effective at preventing another attack: one on the embedee’s reputation. We consider any cross-site authenticated request to have potential reputational harm as consumers become more privacy conscious. Therefore a first-party or sibling cross-site causing an embedded resource to be requested with the user’s authentication cookies would constitute an attack on the reputation of that cross-site’s owner. This is also a reason we require this API to be used in a secure context : so a network adversary cannot induce an embedee to use this API.
The
embedder
has
control
over
which
nested
Documents
have
the
ability
to
become
authenticated,
or
even
display
a
permission
request
to
the
user
via
the
Permission
Policy
and
nested
Document
sandboxing.
7.2. Notification abuse
Notification
abuse
was
also
considered
while
specifying
the
Storage
Access
API.
Specifically,
we
require
user
interaction
in
the
nested
Document
and
consume
that
rejection
on
a
denial
to
restrict
the
conditions
a
permission
prompt
will
be
shown
to
the
user.
This
mitigates
attacks
such
as
re-requesting
a
permission
immediately
after
the
user
denies
it.
8. Automation
For the purposes of user-agent automation and application testing, this document defines the following extension command for the [WebDriver] specification.
8.1. Set Storage Access
| HTTP Method | URI Template |
|---|---|
| POST | /session/{session id}/storageaccess |
The Set Storage Access extension command modifies the storage access policy for the current browsing context .
The remote end steps are:
-
Let blocked be the result of getting a property from parameters named
blocked. -
If blocked is not a boolean return a WebDriver error with WebDriver error code invalid argument .
-
Let embedded origin be the result of getting a property from parameters named
origin. -
If embedded origin is not a single U+002A ASTERISK character (*), then:
-
Let parsedURL be the the result of running the URL parser on embedded origin .
-
If parsedURL is failure, then return a WebDriver error with WebDriver error code invalid argument .
-
Set embedded origin to parsedURL ’s origin .
-
-
If the current browsing context is not a top-level browsing context return a WebDriver error with WebDriver error code unsupported operation .
-
Let doc be the current browsing context ’s active document .
-
Let settings be doc ’s relevant settings object .
-
Let top-level site be the result of obtaining a site from settings ’s origin .
-
If embedded origin is a single U+002A ASTERISK character (*), then:
-
If blocked is
true, then:-
Run an implementation-defined set of steps to ensure that no site has access to its unpartitioned data when loaded in a third party context on top-level site .
-
-
Otherwise, if blocked is
false, then:-
Run an implementation-defined set of steps to ensure that any site has access to its unpartitioned data when loaded in a third party context on top-level site .
-
-
-
Otherwise:
-
If embedded origin is same site with settings ’s origin return a WebDriver error with WebDriver error code unsupported operation .
-
If blocked is
true, then:-
Run an implementation-defined set of steps to ensure that embedded origin does not have access to its unpartitioned data when loaded in a third party context on top-level site .
-
-
Otherwise, if blocked is
false, then:-
Run an implementation-defined set of steps to ensure that embedded origin has access to its unpartitioned data when loaded in a third party context on top-level site .
-
-
-
If the above implementation-defined step of steps resulted in failure, return a WebDriver error with WebDriver error code unknown error .
-
Return success with data
null.
Acknowledgements
This specification builds on the foundations created by former editors John Wilander, who invented the Storage Access API, and Theresa O’Connor, who wrote significant portions of the initial text. We are grateful for their ideas and contributions.
Many thanks to Anne van Kesteren, Ben Kelly, Brad Girardeau, Brad Hill, Brady Eidson, Brandon Maslen, Chris Mills, Dave Longley, Domenic Denicola, Ehsan Akhgari, Geoffrey Garen, Jack Frankland, James Coleman, James Hartig, Jeffrey Yasskin, Kushal Dave, Luís Rudge, Maciej Stachowiak, Matias Woloski, Mike O’Neill, Mike West, Pete Snyder, Rob Stone, Stefan Leyhane, Steven Englehardt, Travis Leithead, Yan Zhu, Zach Edwards, and everyone who commented on whatwg/html#3338 , privacycg/proposals#2 , and privacycg/storage-access/issues for their feedback on this proposal.
Thanks to the WebKit Open Source Project for allowing us to use the Storage Access API Prompt image, which was originally published on webkit.org .