1. Introduction
The web platform provides an ever-expanding set of features and APIs, offering richer functionality, better developer ergonomics, and improved performance. However, a missing piece is the ability for the developer to selectively enable, disable, or modify the behavior of some of these browser features and APIs within their application:
- The developer may want to selectively disable access to certain browser features and APIs to "lock down" their application, as a security or performance precaution, to prevent own and third-party content executing within their application from introducing unwanted or unexpected behaviors within their application.
- The developer may want to selectively enable access to certain browser features and APIs which may be disabled by default - e.g. some features may be disabled by default in embedded context unless explicitly enabled; some features may be subject to other policy requirements.
- The developer may want to use the policy to assert a promise to a client or an embedder about the use—or lack of thereof—of certain features and APIs. For example, to enable certain types of "fast path" optimizations in the browser, or to assert a promise about conformance with some requirements set by other embedders - e.g. various social networks, search engines, and so on.
This specification defines a policy mechanism that addresses the above use cases.
This specification used to be named Feature Policy.
2. Examples
SecureCorp Inc. wants to disable use of Fullscreen and Geolocation APIs within their application. It can do so by delivering the following HTTP response header to define a permissions policy:
Permissions-Policy : fullscreen=(), geolocation=()
By specifying an empty origin list, the specified features will be disabled for all documents, including nested documents, regardless of their origin.
Geolocation
is
disabled
by
default
in
all
cross-origin
frames.
FastCorp
Inc.
has
a
specific
cross-origin
iframe
on
their
site
for
which
it
wants
to
enable
geolocation.
It
can
do
so
by
including
an
"
allow
"
attribute
on
the
iframe
element:
<iframe src="https://other.com/map" allow ="geolocation"></iframe>
Iframe attributes can selectively enable features in certain frames, and not in others, even if those contain documents from the same origin.
SecureCorp
Inc.
wants
to
completely
disable
use
of
the
Geolocation
API
within
all
descendant
navigables
except
for
its
own
origin
and
those
whose
origin
is
"
https://example.com
",
even
in
the
presence
of
an
attacker
who
can
embed
their
own
iframes
on
SecureCorp’s
pages.
It
can
do
this
by
delivering
the
following
HTTP
response
header
to
define
a
restricted
permissions
policy
for
Geolocation:
Permissions-Policy : geolocation=(self "https://example.com")
The
allowlist
is
a
list
of
one
or
more
origins,
which
can
include
the
application’s
origin,
optionally
with
the
keyword
"
self
",
and
any
third-party
origin.
With
this
policy
in
effect,
it
can
then
use
the
"
allow
"
iframe
attribute
as
usual
to
grant
geolocation
to
certain
frames,
but
only
those
frames
hosting
content
from
http://example.com
or
SecureCorp
itself
will
actually
be
granted
the
ability
to
use
that
API.
SecureCorp
Inc.
restructured
its
domains
and
now
needs
to
needs
to
delegate
use
of
the
Geolocation
API
to
its
origin
("
https://example.com
")
as
well
as
three
subdomains
("
https://geo.example.com
",
"
https://geo2.example.com
",
and
"
https://new.geo2.example.com
").
This
needs
to
be
accomplished
while
still
disabling
the
use
of
the
Geolocation
API
within
all
other
browsing
contexts.
It
can
do
this
by
delivering
the
following
HTTP
response
header:
Permissions-Policy: geolocation=(self "https://example.com" "https://geo.example.com" "https://geo2.example.com" "https://new.geo2.example.com")
This
works,
but
if
SecureCorp
Inc.
feels
safe
delegating
to
any
subdomains
on
"
https://example.com
"
the
HTTP
response
header
could
instead
be:
Permissions-Policy: geolocation=(self "https://example.com" "https://*.example.com")
Not
only
would
the
above
header
permit
"
https://geo.example.com
",
"
https://geo2.example.com
",
and
"
https://new.geo2.example.com
"
to
use
the
Geolocation
API,
but
any
other
subdomains
of
"
https://example.com
"
could
use
it
too.
Note
that
"
https://example.com
"
is
not
covered
by
the
allowlist
entry
"
https://*.example.com
"
and
must
also
be
added.
SecureCorp
Inc.
restructured
its
services
and
now
needs
to
needs
to
delegate
use
of
the
Geolocation
API
to
its
origin
("
https://example.com
")
as
well
as
three
non-default
ports
("
https://example.com:444
",
"
https://example.com:445
",
and
"
https://example.com:446
").
This
needs
to
be
accomplished
while
still
disabling
the
use
of
the
Geolocation
API
within
all
other
browsing
contexts.
It
can
do
this
by
delivering
the
following
HTTP
response
header:
Permissions-Policy: geolocation=(self "https://example.com" "https://example.com:444" "https://example.com:445" "https://example.com:446")
This
works,
but
if
SecureCorp
Inc.
feels
safe
delegating
to
any
ports
on
"
https://example.com
"
the
HTTP
response
header
could
instead
be:
Permissions-Policy: geolocation=(self "https://example.com:*")
Not
only
would
the
above
header
permit
"
https://example.com:444
",
"
https://example.com:444
",
and
"
https://example.com:445
"
to
use
the
Geolocation
API,
but
any
other
ports
on
"
https://example.com
"
could
use
it
too.
3. Other and related mechanisms
[HTML5]
defines
a
sandbox
attribute
for
iframe
elements
that
allows
developers
to
reduce
the
risk
of
including
potentially
untrusted
content
by
imposing
restrictions
on
content’s
abilities
-
e.g.
prevent
it
from
submitting
forms,
running
scripts
and
plugins,
and
more.
The
sandbox
directive
defined
by
[CSP2]
extends
this
capability
to
any
resource,
framed
or
not,
to
ask
for
the
same
set
of
restrictions
-
e.g.
via
an
HTTP
response
header
(
Content-Security-Policy:
sandbox
).
These
mechanisms
enable
the
developer
to:
- Set and customize a sandbox policy on any resource via CSP.
-
Set
and
customize
individual
sandbox
policies
on
each
iframe
element within their application.
However, there are several limitations to the above mechanism: the developer cannot automatically apply a policy across all contexts, which makes it hard or impossible to enforce consistently in some cases (e.g. due to third-party content injecting frames, which the developer does not control); there is no mechanism to selectively enable features that may be off by default; the sandbox mechanism automatically disables all sandbox features, and requires the developer to opt back in to each of them, so it is impossible to extend the set of sandbox features without significant compatibility risk.
Permissions Policy is intended to be used in combination with the sandbox mechanism (i.e. it does not duplicate feature controls already covered by sandbox), and provides an extensible mechanism that addresses the above limitations.
4. Framework
4.1. Policy-controlled Features
A policy-controlled feature is an API or behaviour which can be enabled or disabled in a document by referring to it in a permissions policy .
Policy-controlled features are identified by tokens, which are character strings used in policy directives .
Each policy-controlled feature has a default allowlist , which defines whether that feature is available in documents in top-level traversables, and how access to that feature is inherited in child navigables.
A user agent has a set of supported features , which is the set of features which it allows to be controlled through policies. User agents are not required to support every feature .
4.2. Policies
A declared policy is a struct with the following items :
- declarations
-
an ordered map from features to allowlists
- reporting configuration
-
an ordered map from features to strings
A permissions policy is a struct with the following items :
- inherited policy
-
an ordered map from features to "
Enabled
" or "Disabled
" - declared policy
An
empty
permissions
policy
is
a
permissions
policy
that
has
an
inherited
policy
which
contains
"
Enabled
"
for
every
supported
feature
,
a
declared
policy
whose
declarations
and
reporting
configuration
are
both
empty
ordered
maps
.
4.3. Inherited policies
The inherited policy for a feature feature is the value in the inherited policy whose key is feature . After a permissions policy has been initialized, its inherited policy will contain a value for each supported feature .
Upon
both
creation
and
navigation,
Each
Document
inherits
a
set
of
policies
from
its
parent
frame,
or
in
the
case
of
the
Document
in
a
top-level
traversable
,
from
the
defined
defaults
for
each
policy-controlled
feature
.
This
inherited
policy
determines
the
initial
state
("
Enabled
"
or
"
Disabled
")
of
each
feature,
and
whether
it
can
be
controlled
by
a
declared
policy
in
the
Document
.
In
a
Document
in
a
top-level
traversable
,
the
inherited
policy
is
based
on
defined
defaults
for
each
feature.
In
a
Document
in
a
child
navigable
,
the
inherited
policy
is
based
on
the
parent
document’s
permissions
policy,
as
well
as
the
child
navigable
's
container
policy
.
4.4. Header policies
A header policy is a list of policy directives delivered via an HTTP header with a document. This forms the document’s permissions policy ’s declared policy .
4.5. Container policies
In addition to the header policy , each child navigable has a container policy , which is a policy directive , which may be empty. The container policy can set by attributes on the navigable container .
The
container
policy
for
a
child
navigable
influences
the
inherited
policy
of
any
Document
loaded
into
that
navigable.
(See
§ 9.7
Define
an
inherited
policy
for
feature
in
container
at
origin
).
iframe
allowfullscreen
,
and
allow
attributes.
Future
revisions
to
this
spec
may
introduce
a
mechanism
to
explicitly
declare
the
full
container
policy
.
4.6. Policy directives
A policy directive is an ordered map , mapping policy-controlled features to corresponding allowlists of origins.
A policy directive is represented in HTTP headers as the serialization of an sf-dictionary structure, and in and HTML attributes as its ASCII serialization.
4.7. Allowlists
A permissions policy allowlist is conceptually a set of origins . An allowlist may be either:
-
The
special
value
*
, which represents every origin, or -
A
struct
containing:
- expressions , which is an ordered set of permissions-source-expression
-
self-origin
,
which
is
an
origin
or
null
-
src-origin
,
which
is
an
origin
or
null
'self'
,
'src'
,
and
'none'
can
appear
in
the
text
representation
of
allowlists
in
headers
and
attribute
strings.
These
keywords
are
always
interpreted
in
context
during
parsing,
and
only
the
origins
which
they
refer
to
are
stored
in
the
allowlist.
The
keywords
themselves
are
not
part
of
the
allowlist.
To determine whether an allowlist matches an origin origin , run these steps:
-
If the allowlist is the special value
*
, then return true.
Note: We are not using the CSP variant of wildcard matching as it requires the HTTPS scheme.
-
If the allowlist ’s self-origin is not null and it is same origin-domain with origin , then return true.
-
If the allowlist ’s src-origin is not null and it is same origin-domain with origin , then return true.
-
If origin is an opaque origin , return false.
-
Let url be the result of calling the url parser on the serialization of origin .
-
For each permissions-source-expression item in the allowlist ’s expressions :
-
If the result of running Does url match expression in origin with redirect count? on url , item , origin , and 0 is true then return true.
-
-
Return false.
4.8. Default Allowlists
Every
policy-controlled
feature
has
a
default
allowlist
.
The
default
allowlist
determines
whether
the
feature
is
allowed
in
a
Document
with
no
declared
policy
in
a
top-level
traversable
,
and
also
whether
access
to
the
feature
is
automatically
delegated
to
documents
in
child
navigables
.
The default allowlist for a feature is one of these values:
-
*
-
The
feature
is
allowed
in
Document
s in top-level traversables by default, as well as those in all child navigables . It can be disallowed in child navigables by explicitly supplying a container policy on the navigable container that overrides this default (or in any navigable , by delivering theDocument
with a suitablePermissions-Policy
header). -
'self'
-
The
feature
is
allowed
in
documents
in
top-level
traversables
by
default,
as
well
as
those
in
child
navigables
whose
document
is
same
origin
with
its
parent
's
document
,
when
allowed
in
that
Document
. It is disallowed by default in child navigables whose document is cross-origin with its parent 's document . -
none
-
The
feature
is
not
allowed
in
Document
s in top-level traversables by default, as well as those in all child navigables . It can be allowedDocument
s in top-level traversables by delivering theDocument
with a suitablePermissions-Policy
header). It can be allowed in child navigables if it is allowed in the parentDocument
by explicitly supplying a container policy on the navigable container that overrides this default and by delivering theDocument
with a suitablePermissions-Policy
header.
5. Permissions Policy Serialization
5.1. HTML attribute serialization
Policy Directives in HTML attributes are represented as their ASCII serialization, with the following ABNF:
serialized-permissions-policy = serialized-policy-directive *(";" serialized-policy-directive) serialized-policy-directive = feature-identifier RWS allow-list feature-identifier = 1*( ALPHA / DIGIT / "-") allow-list = allow-list-value *(RWS allow-list-value) allow-list-value = permissions-source-expression / "*" / "'self'" / "'src'" / "'none'" permissions-source-expression = scheme-source / host-source
'self'
"
may
be
used
as
an
origin
in
an
allowlist
.
When
it
is
used
in
this
way,
it
will
refer
to
the
origin
of
the
Document
which
contains
the
permissions
policy
.
5.2. Structured header serialization
Policy Directives in HTTP headers are represented as Structured Fields. [RFC8941]In this representation, a policy directive is represented by a Dictionary.
Each Dictionary Member associates a feature with an allowlist . The Member Names must be Tokens. If a token does not name one of the user agent’s supported features , then the Dictionary Member will be ignored by the processing steps.
The Member Values represent allowlists , and must be one of:
-
a String containing the ASCII permissions-source-expression
-
the Token
*
-
the Token
self
-
an Inner List containing zero or more of the above items.
Member
Values
may
have
a
Parameter
named
"report-to"
,
whose
value
must
be
a
String.
Any
other
parameters
will
be
ignored.
Any other items inside of an Inner List will be ignored by the processing steps, and the Member Value will be processed as if they were not present. Member Values of any other form will cause the entire Dictionary Member to be ignored by the processing steps.
6. Delivery
6.1.
`
Permissions-Policy
`
HTTP
Header
Field
The
`
Permissions-Policy
`
HTTP
header
field
can
be
used
in
the
response
(server
to
client)
to
communicate
the
permissions
policy
that
should
be
enforced
by
the
client.
`
Permissions-Policy
`
is
a
structured
header.
Its
value
must
be
a
dictionary.
It’s
ABNF
is:
PermissionsPolicy = sf-dictionary
The semantics of the dictionary are defined in § 5.2 Structured header serialization .
The processing steps are defined in § 9.2 Construct policy from dictionary and origin .
6.2.
The
allow
attribute
of
the
iframe
element
iframe
elements
have
an
allow
attribute,
which
contains
an
ASCII-serialized
policy
directive
.
The
allowlist
for
the
features
named
in
the
attribute
may
be
empty;
in
that
case,
the
default
value
for
the
allowlist
is
'src'
,
which
represents
the
origin
of
the
URL
in
the
iframe’s
src
attribute.
When
not
empty,
the
allow
attribute
will
result
in
adding
an
allowlist
for
each
recognized
feature
to
the
iframe
element’s
content
navigable
's
container
policy
,
when
it
is
constructed.
6.3. Additional attributes to support legacy features
Some
features
controlled
by
Permissions
Policy
have
existing
iframe
attributes
defined.
This
specification
redefines
these
attributes
to
influence
the
iframe
's
content
navigable
's
container
policy
.
6.3.1. allowfullscreen
The
allowfullscreen
iframe
attribute
controls
access
to
requestFullscreen()
.
If
the
iframe
element
has
an
allow
attribute
whose
value
contains
the
token
"
fullscreen
",
then
the
allowfullscreen
attribute
must
have
no
effect.
Otherwise,
the
presence
of
an
allowfullscreen
attribute
on
an
iframe
will
result
in
adding
an
allowlist
of
*
for
the
"
fullscreen
"
feature
to
the
iframe
element’s
content
navigable
's
container
policy
,
when
it
is
constructed.
<iframe
allow="fullscreen">
,
and
is
for
compatibility
with
existing
uses
of
allowfullscreen
.
If
allow="fullscreen"
and
allowfullscreen
are
both
present
on
an
iframe
element,
then
the
more
restrictive
allowlist
of
allow="fullscreen"
will
be
used.
7. Policy Introspection from Scripts
7.1. Overview
The current policy which is in effect in a document can be observed by scripts. This can be used to make decisions, for instance, about what user interface to display, in cases where it is not possible to determine otherwise whether a feature is enabled or not. (Some features may not have any observable failure mode, or may have unwanted side effects to feature detection.)
Documents
and
iframes
both
provide
a
PermissionsPolicy
object
which
can
be
used
to
inspect
the
permissions
policies
which
apply
to
them.
7.1.1. Document policies
To
retreive
the
currently
effective
policy,
use
document.permissionsPolicy
.
This
returns
a
PermissionsPolicy
object,
which
can
be
used
to:
-
query the state (allowed or denied) in the current document for a given feature,
-
get a list of all available features (allowed or not) in the current document,
-
get a list of all allowed features in the current document, or
-
get the allowlist for a given feature in the current document.
<!doctype html> <script> const policy = document.permissionsPolicy; // This will be true if this document can use WebUSB. const can_use_usb = policy.allowsFeature('usb'); // True if a new frame at https://example.com will be allowed to use WebXR. if (policy.allowsFeature('xr-spatial-tracking', 'https://example.com')) { // Show UI to create frame at https://example.com. } else { // Show an alternative UI. } // Get the list of origins which are allowed to request payment. The result // will be a list of explicit origins, or the single element ['*'] if all // origins are allowed. const allowed_payment_origins = policy.getAllowlistForFeature('payment'); // Get the list of all features supported in this document (even those // which are not allowed). The result will be an array of strings, each // representing a feature. const all_features = policy.features(); if (all_features.includes('geolocation')) { // Append a child frame to a third-party map service. } </script>
7.1.2. Frame policies
It is also possible to inspect the policy on an iframe element, from the document which contains it. The policy object in this case represents the observable policy for the frame, which depends only on the current document and the attributes of the iframe element. It does not reveal whether a feature is actually currently allowed in the frame, as the document in the frame may have applied its own policy via an HTTP header, or may have navigated away from its initial location to a new origin. Revealing the effective policy in the iframe element’s nested navigable in that case could leak information about the behaviour of a cross-origin document.
<!doctype html> <iframe id="frame" allow="fullscreen; xr-spatial-tracking"></iframe> <script> const iframe_element = document.getElementById("frame"); const iframe_policy = iframe_element.permissionsPolicy; // True if the framed document will be allowed to use WebXR if (iframe_policy.allowsFeature('xr-spatial-tracking')) { // display virtual reality controls } </script>
The observable policy on an iframe element is independent of any actual content loaded into the frame (to avoid cross-origin information leakage,) or even whether it is in a document tree.
<!doctype html> <!-- this frame should not be allowed to use fullscreen when the document in its src attribute is loaded in it --> <iframe id="frame" allow="fullscreen https://example.com" src="https://example.net/" ></iframe> <script> const iframe_element = document.getElementById("frame"); const iframe_policy = iframe_element.permissionsPolicy; // This will be false, as the URL listed in the src attribute is not allowed // by policy to use fullscreen. const is_fullscreen_allowed_in_frame = iframe_policy.allowsFeature('fullscreen'); const new_frame = document.createElement('iframe'); new_frame.allow = 'sync-xhr'; // This will be true, as the iframe is allowed to use sync-xhr at whatever URL is // mentioned in its src attribute, even though that attribute is not yet set. const is_sync_xhr_allowed = new_frame.permissionsPolicy.allowsFeature('sync-xhr'); </script>
7.2. The permissionsPolicy object
[Exposed =Window ]interface {
PermissionsPolicy boolean (
allowsFeature DOMString ,
feature optional DOMString );
origin sequence <DOMString >();
features sequence <DOMString >();
allowedFeatures sequence <DOMString >(
getAllowlistForFeature DOMString ); };
feature {partial interface Document { [SameObject ]readonly attribute PermissionsPolicy ; };
permissionsPolicy partial interface HTMLIFrameElement { [SameObject ]readonly attribute PermissionsPolicy ; };
permissionsPolicy
A
PermissionsPolicy
object
has
an
associated
node
,
which
is
a
Node
.
The
associated
node
is
set
when
the
PermissionsPolicy
object
is
created.
A
PermissionsPolicy
object
has
a
default
origin
,
which
is
an
origin
,
whose
value
depends
on
the
state
of
the
PermissionsPolicy
object’s
associated
node
:
-
If the
PermissionsPolicy
object’s associated node is aDocument
, then its default origin is theDocument
's origin . -
If the
PermissionsPolicy
object’s associated node is anElement
, then its default origin is theElement
's declared origin .
Each
Document
has
a
policy
object
,
which
is
a
PermissionsPolicy
instance
whose
associated
node
is
that
Document
.
A
Document
's
permissionsPolicy
IDL
attribute,
on
getting,
must
return
the
Document
's
policy
object
.
Each
iframe
element
has
a
policy
object
,
which
is
a
PermissionsPolicy
instance
whose
associated
node
is
that
element.
An
iframe
's
permissionsPolicy
IDL
attribute,
on
getting,
must
return
the
iframe
's
policy
object
.
The
allowsFeature(feature,
origin)
method
must
run
the
following
steps:
-
If origin is omitted, set origin to this
PermissionsPolicy
object’s default origin . -
Let policy be the observable policy for this
PermissionsPolicy
object’s associated node . -
If feature is allowed by policy for origin , return true.
-
Otherwise, return false.
The
features()
method
must
run
the
following
steps:
-
Set result to an empty ordered set.
-
For each supported feature feature :
-
Append feature to result .
-
-
return result
The
allowedFeatures()
method
must
run
the
following
steps:
-
Set result to an empty ordered set.
-
Let origin be this
PermissionsPolicy
object’s default origin . -
Let policy be the observable policy for this
PermissionsPolicy
object’s associated node . -
For each supported feature feature :
-
If feature is allowed by policy for origin , append feature to result .
-
-
return result
The
getAllowlistForFeature(feature)
method
must
run
the
following
steps:
-
Set result to an empty list.
-
Let origin be this
PermissionsPolicy
object’s default origin . -
Let policy be the observable policy for this
PermissionsPolicy
object’s associated node . -
If feature is not allowed in policy for origin , return result
-
Let allowlist be policy ’s declared policy [ feature ]'s declarations .
-
If allowlist is the special value
*
:-
Append "
*
" to result -
Return result .
-
-
If the allowlist ’s self-origin is not null, append the serialization of it to result .
-
If the allowlist ’s src-origin is not null, append the serialization of it to result .
-
Otherwise, for each permissions-source-expression item in allowlist ’s expressions :
-
Append item to result
-
-
Return result .
The observable policy for any Node is a permissions policy , which contains the information about the policy in the navigable represented by that Node which is visible from the current document.
To get the observable policy for a Document document , return document ’s permissions policy.
To get the observable policy for an Element node , run the following steps:
-
Let inherited policy be an empty ordered map .
-
For each supported feature feature :
-
Let isInherited be the result of running Define an inherited policy for feature in container at origin on feature , node and node ’s declared origin .
-
Set inherited policy [ feature ] to isInherited .
-
-
Return a new permissions policy with inherited policy inherited policy , declared policy a struct with both declarations and reporting configuration new ordered maps .
To get the declared origin for an Element node , run the following steps:
-
If node ’s node document ’s sandboxed origin browsing context flag is set, then return a new opaque origin .
-
If node ’s
sandbox
attribute is set, and does not contain theallow-same-origin
keyword, then return a new opaque origin . -
If node ’s
srcdoc
attribute is set, then return node ’s node document ’s origin. -
If node ’s
src
attribute is set:-
Let url be the result of parsing node ’s src attribute, relative to node ’s node document .
-
If url is not failure, return url ’s origin.
-
-
Return node ’s node document ’s origin.
The
declared
origin
concept
is
intended
to
represent
the
origin
of
the
document
which
the
embedding
page
intends
to
load
into
a
frame.
This
means,
for
instance,
that
if
the
browser
does
not
support
the
sandbox
or
srcdoc
attributes,
it
should
not
take
those
attributes
into
account
when
computing
the
declared
origin.
8. Reporting
Permissions policy violation reports indicate that some behavior of the Document has violated a permissions policy. It is up to the specification of each individual policy-controlled feature to define what it means to violate that policy, and how to determine when such a violation has occurred.
Permissions policy violation reports have the report type "permissions-policy-violation".
Permissions
policy
violation
reports
are
visible
to
ReportingObserver
s
.
[Exposed =Window ]interface :
PermissionsPolicyViolationReportBody ReportBody {readonly attribute DOMString ;
featureId readonly attribute DOMString ?;
sourceFile readonly attribute long ?;
lineNumber readonly attribute long ?;
columnNumber readonly attribute DOMString ; };
disposition
A
permissions
policy
violation
report
’s
body
,
represented
in
JavaScript
by
PermissionsPolicyViolationReportBody
,
contains
the
following
fields:
-
featureId : The string identifying the policy-controlled feature whose policy has been violated . This string can be used for grouping and counting related reports.
-
sourceFile : If known, the file where the violation occured, or null otherwise.
-
lineNumber : If known, the line number in sourceFile where the violation occured, or null otherwise.
-
columnNumber : If known, the column number in sourceFile where the violation occured, or null otherwise.
-
disposition : A string indicating whether the violated permissions policy was enforced in this case. disposition will be set to "enforce" if the policy was enforced, or "report" if the violation resulted only in this report being generated (with no further action taken by the user agent in response to the violation).
8.1.
`
Permissions-Policy-Report-Only
`
HTTP
Header
Field
The
`
Permissions-Policy-Report-Only
`
HTTP
header
field
can
be
used
in
the
response
(server
to
client)
to
communicate
a
permissions
policy
that
should
not
be
enforced
by
the
client,
but
instead
should
be
used
to
trigger
reports
to
be
sent
if
any
policy
declared
within
it
would
have
been
violated,
had
the
policy
been
active.
`
Permissions-Policy-Report-Only
`
is
a
structured
header.
Its
value
must
be
a
dictionary.
The semantics of the dictionary are defined in § 5.2 Structured header serialization .
The processing steps are defined in § 9.2 Construct policy from dictionary and origin .
9. Algorithms
9.1. Process response policy
-
Let header name be "
Permissions-Policy-Report-Only
" if report-only is True, or "Permissions-Policy
" otherwise. -
Let parsed header be the result of executing get a structured field value given header name and "dictionary" from response ’s header list .
-
If parsed header is null, return an empty ordered map .
-
Let policy be the result of executing Construct policy from dictionary and origin on parsed header and origin .
-
Return policy .
9.2. Construct policy from dictionary and origin
-
Let declarations be an empty ordered map .
-
Let reporting-config be an empty ordered map .
-
For each feature-name → ( value , params ) of dictionary :
-
If feature-name does not identify any recognized policy-controlled feature , then continue .
-
Let feature be the policy-controlled feature identified by feature-name .
-
If params ["report-to"] exists, and is a string, then set reporting-config [ feature ] to params ["report-to"].
-
Let allowlist be a new allowlist .
-
If value is the token
*
, or if value is a list which contains the token*
, set allowlist to the special value*
. -
Otherwise:
-
If value is the token
self
, let allowlist ’s self-origin be origin . -
Otherwise if value is a list , then for each element in value :
-
If element is the token
self
, let allowlist ’s self-origin be origin . -
If element is a valid permissions-source-expression , append element to allowlist ’s expressions .
-
-
-
Set declarations [ feature ] to allowlist .
-
-
Return « declarations , reporting-config ».
9.3. Parse policy directive
-
Let directive be an empty ordered map .
-
For each serialized-declaration returned by strictly splitting value on the delimiter U+003B (;) :
-
Let tokens be the result of splitting serialized-declaration on ASCII whitespace.
-
If tokens is an empty list, then continue .
-
Let feature-name be the first element of tokens .
-
If feature-name does not identify any recognized policy-controlled feature , then continue .
-
Let feature be the policy-controlled feature identified by feature-name .
-
Let targetlist be the remaining elements, if any, of tokens .
-
Let allowlist be a new allowlist .
-
If any element of targetlist is the string "
*
", set allowlist to the special value*
. -
Otherwise:
-
If targetlist is empty and target origin is given, let allowlist ’s src-origin be target origin .
-
For each element in targetlist :
-
If element is an ASCII case-insensitive match for "
'self'
":-
Let allowlist ’s self-origin be container origin .
-
Continue to the next element .
-
-
If target origin is given, and element is an ASCII case-insensitive match for "
'src'
":-
Let allowlist ’s src-origin be target origin .
-
Continue to the next element .
-
-
Let result be the result of executing the URL parser on element .
-
If result is not failure:
-
Let target be the origin of result .
-
If target is not an opaque origin , append the serialization of target to allowlist ’s expressions .
-
-
-
-
Set directive [ feature ] to allowlist .
-
-
Return directive
9.4. Process permissions policy attributes
-
If element is not an
iframe
element, then return an empty policy directive . -
Let container policy be the result of running Parse policy directive given the value of element ’s
allow
attribute, the origin of element ’s node document , and element ’s declared origin . -
If element ’s
allowfullscreen
attribute is specified, and container policy does not contain an entry for thefullscreen
feature .-
Set container policy [
fullscreen
] = the special value*
.
-
-
Return container policy .
9.5. Create a Permissions Policy for a navigable
-
Assert: If not null, container is a navigable container .
-
Let inherited policy be a new ordered map .
-
-
Let isInherited be the result of running Define an inherited policy for feature in container at origin on feature , container and origin .
-
Set inherited policy [ feature ] to isInherited .
-
-
Let policy be a new permissions policy , with inherited policy inherited policy and declared policy «[], []».
-
Return policy .
9.6. Create a Permissions Policy for a navigable from response
-
Let policy be the result of running Create a Permissions Policy for a navigable given container and origin .
-
Let d be the result of running Process response policy given response , origin and report-only .
-
For each feature → allowlist of d ’s declarations :
-
If policy ’s inherited policy [ feature ] is true, then set policy ’s declared policy ’s declarations [ feature ] to allowlist .
-
-
Set policy ’s declared policy [ feature ]'s reporting configuration to d ’s reporting configuration .
-
Return policy .
9.7. Define an inherited policy for feature in container at origin
Document
in
that
container
(
origin
),
this
algorithm
returns
the
inherited
policy
value
for
feature
.
-
If container is null, return "
Enabled
". -
If the result of executing Get feature value for origin on feature , container ’s node document , and container ’s node document ’s origin is "
Disabled
", return "Disabled
". -
If the result of executing Get feature value for origin on feature , container ’s node document , and origin is "
Disabled
", return "Disabled
". -
Let container policy be the result of running Process permissions policy attributes on container .
-
If feature exists in container policy :
-
If feature ’s default allowlist is
*
, return "Enabled
". -
If feature ’s default allowlist is
'self'
, and origin is same origin with container ’s node document ’s origin , return "Enabled
". -
Otherwise return "
Disabled
".
9.8. Get feature value for origin
Document
object
(
document
),
and
an
origin
(
origin
),
this
algorithm
returns
"
Disabled
"
if
feature
should
be
considered
disabled,
and
"
Enabled
"
otherwise.
-
Let policy be document ’s permissions policy .
-
If policy ’s inherited policy for feature is "
Disabled
", return "Disabled
". -
If feature is present in policy ’s declared policy :
-
If policy ’s declared policy ’s declarations [ feature ] matches origin , then return "
Enabled
". -
Otherwise return "
Disabled
".
-
-
ReturnIf feature ’s default allowlist is*
orself
, return "Enabled
". -
Return "
Disabled
".
9.9. Check permissions policy
Document
object
(
document
Disabled
"
if
feature
should
be
considered
disabled,
and
"
Enabled
"
otherwise.
-
If policy ’s inherited policy for feature is "
Disabled
", return "Disabled
". -
If feature is present in policy ’s declared policy :
-
If policy ’s declared policy ’s declarations [ feature ] matches origin , then return "
Enabled
". -
Otherwise return "
Disabled
".
-
-
If feature ’s default allowlist is
*
, return "Enabled
". -
Let document origin be document ’s origin .
If feature ’s default allowlist is
'self'
, and origin is same origin with document origin , return "Enabled
".-
If document is a headerless document, return "
Enabled
". Return "
Disabled
".
9.10. Is feature enabled in document for origin?
Document
object
(
document
),
an
origin
(
origin
),
and
an
optional
boolean
(
report
),
with
a
default
value
of
True,
this
algorithm
returns
"
Disabled
"
if
feature
should
be
considered
disabled,
and
"
Enabled
"
otherwise.
If
report
is
True,
then
it
will
also
generate
and
queue
a
report
if
the
feature
is
not
enabled
in
either
document
’s
permissions
policy
or
document
’s
report-only
permissions
policy
Note: The default value of True for report means that most permissions policy checks will generate a violation report if the feature is not enabled. This is the expected result, as most checks are for an actual attempted use of the feature. If a call to this algorithm is performed just to query the state of a feature, and does not represent an actual attempt to use the feature, then report should be set to False.
-
Let policy be document ’s permissions policy .
-
Let report-only policy be document ’s report-only permissions policy .
-
Let result be the result of calling Check permissions policy , given policy , feature , origin , and document
’s origin .. -
Let report-only result be the result of calling Check permissions policy , given report-only policy , feature , origin , and document ’s origin .
-
If report is True:
-
Let settings be document ’s environment settings object .
-
If result is "
Disabled
":-
Let endpoint be the result of calling Get the reporting endpoint for a feature given feature and policy .
-
Call Generate report for violation of permissions policy on settings given feature , settings , "
Enforce
", and endpoint .
-
-
Else, if report-only result is "
Disabled
":-
Let report-only endpoint be the result of calling Get the reporting endpoint for a feature given feature and report-only policy .
-
Call Generate report for violation of permissions policy on settings given feature , settings , "
Report
", and report-only endpoint .
-
-
-
Return result
9.11. Get the reporting endpoint for a feature
-
Let config be policy ’s declared policy 's reporting configuration .
-
If config [ feature ] exists, return config [ feature ].
-
Return null.
9.12. Generate report for violation of permissions policy on settings
-
Let body be a new
PermissionsPolicyViolationReportBody
, initialized as follows:- featureId
-
feature ’s string representation.
- sourceFile
-
null
- lineNumber
-
null
- columnNumber
-
null
- disposition
-
disposition
-
If the user agent is currently executing script, and can extract the source file’s URL, line number, and column number from settings , then set body ’s sourceFile , lineNumber , and columnNumber accordingly.
-
Execute generate and queue a report with body , "permissions-policy-violation", endpoint , and settings .
9.13. Should request be allowed to use feature?
true
if
the
request
should
be
allowed
to
use
feature
,
and
false
otherwise.
-
Set window to request ’s window .
-
If window is not a
Window
, returnfalse
.Permissions Policy within non-Window contexts (WorkerGlobalScope
orWorkletGlobalScope
) is being figured out in issue #207 . After that’s resolved, update this algorithm to allow fetches initiated within these contexts to use policy-controlled features. Until that’s resolved, disallow all policy-controlled features (e.g., sending Client Hints to third parties) in these contexts. -
Set document to window ’s associated
Document
. -
Let origin be request ’s origin .
-
Let result be the result of executing Is feature enabled in document for origin? on feature , document , and origin .
-
If result is "
Enabled
", returntrue
. -
Otherwise, return
false
.
10. Changes to other specifications
10.1. Changes to the HTML specification
Every
Document
has
a
report-only
permissions
policy
,
which
is
a
permissions
policy
,
which
is
initially
empty.
In 7.5.1 Shared document creation infrastructure , after step 3, insert the following step:
-
Let reportOnlyPermissionsPolicy be the result of calling Create a Permissions Policy for a navigable from response given navigationParams’s navigable’s container, navigationParams’s origin, navigationParams’s response, and True.
And
in
the
same
section,
in
step
10,
set
the
new
Document
's
11. IANA Considerations
The permanent message header field registry should be updated with the following registration [RFC3864] :
- Header field name
- Permissions-Policy
- Applicable protocol
- http
- Status
- standard
- Author/Change controller
- W3C
- Specification document
- https://www.w3.org/TR/permissions-policy/
12. Privacy and Security
This
specification
standardizes
a
mechanism
for
an
embedding
page
to
set
a
policy
which
will
be
enforced
on
an
embedded
page.
Similar
to
iframe
sandbox
,
this
can
be
done
without
the
express
permission
of
the
embedded
page,
which
means
that
behaviors
of
existing
features
can
be
changed
in
published
web
sites,
by
embedding
them
in
another
document
with
an
appropriate
container
policy.
As such, the biggest privacy and security concerns are:
- Exposure of behavior in a cross-origin subframe to its embedder
- Unanticipated behavior changes in subframes controlled by the embedder
To a degree, these concerns are already present in the web platform, and this specification attempts to at least not make them needlessly worse.
Security and privacy issues may also be caused by the design of individual features, so care must be taken when integrating with this specification. This section attempts to provide some guidance as to what kinds of behaviors could cause such issues.
12.1. Exposure of cross-origin behavior
Features should be designed such that a violation of the policy in a framed document is not observable by documents in other frames. For instance, a hypothetical feature which caused a event to be fired in the embedding document if it is used while disabled by policy, could be used to extract information about the state of an embedded document. If the feature is known only to be used while a user is logged in to the site, for instance, then the embedder could disable that feature for the frame, and then listen for the resulting events to determine whether or not the user is logged in.
The
introspection
API
is
designed
to
only
show
information
about
a
subframe’s
policy
which
could
already
be
deduced
by
the
embedding
document.
This
observable
policy
is
not
affected
by
any
HTTP
headers
delivered
with
the
framed
document,
and
does
not
change
when
the
frame
navigates
itself,
even
if
such
navigation
is
to
a
different
origin,
where
a
different
policy
applies.
Only
navigations
caused
by
setting
the
src
attribute
of
the
<iframe>
element
will
cause
the
observable
policy
to
be
updated.
12.2. Unanticipated behavior changes
The Permissions Policy mechanism grants a document the ability to control which features will and will not be availble in a subframe at the time it is loaded. When a feature represents an existing, long-standing behavior of the web platform, this may mean that existing published content on the web was not written with the expectation that a particular API could fail.
As a practical (though contrived) example, consider a document which uses synchronous XMLHttpRequest to determine whether a user has sufficient privileges to access the page:
<!DOCTYPE html> <h1>Welcome to SecureCorp!</h1> <script> var req = new XMLHttpRequest(); req.open("GET", "/api/security_check.json", false); req.send(); if (req.response == "untrusted user") { // User is not logged in; redirect to a safe page location.href = "/security_check_failed.html"; } </script> <!-- Page continues with assumption that user is logged in -->
If
this
document
is
embedded
by
a
page
which
disables
the
"
sync-xhr
"
feature,
the
call
to
XMLHttpRequest.open()
would
fail,
and
the
security
check
would
be
bypassed.
Note that this sort of behavior forcing is already possible on the web: some features are only allowed in top-level documents, and not in any iframes, and iframe sandboxing can be used in a similar way to embed a frame without access to features which it may be depending on.
In general, this concern is mitigated in two ways:
-
The
vulnerable
page
may
be
served
with
an
X-Frame-Options
HTTP header which does not allow it to be framed by an attacker. - Sites should use feature detection to determine whether an API or behavior is available before attempting to use it, and should handle any documented errors returned or exceptions thrown by the APIs they call.
-
In
the
case
where
feature
detection
is
not
possible,
new
web
content
can
be
written
to
use
the
policy
object to inspect the permissions policy which is currently enforced, and adjust behaviour or user interface accordingly.
Authors integrating their features with Permissions Policy can decide when and how the feature will fail when a document attempts to use it while it is disabled. Authors should attempt to make use of existing failure modes, when they exist, to increase the chance that existing content will already be correctly handling such failures.
12.3. Exposure of embedding policy
Care has been taken to limit the information which an page can infer about the behavior of cross-origin pages which it embeds. It may be possible in some scenarios however, for the embedded page to infer information about its embedder, by examining the policy which the embedder has enforced on it.
This
is
similar
to
the
existing
document.fullscreenEnabled
property,
which
can
be
used
by
the
embedded
document
to
infer
whether
its
embedder
has
granted
it
the
ability
to
use
the
Fullscreen
API.
If
this
is
only
granted
in
certain
cases
—
when
the
user
is
logged
in
to
the
embedding
site,
for
instance
—
then
the
embedded
site
can
learn
something
about
the
state
of
its
embedder.
13. Change log
13.1. Changes since FPWD
-
Expose new algorithms to create a Feature Policy before document is created. Link
-
Remove algorithms no longer needed. Link
-
Change same-origin-domain check to same-origin. Link
-
Change Header and attribute combination from OR to AND semantics. Link
-
Rename to "Permissions Policy". Link
-
Define "Permissions-Policy" as a structured header. Link
-
Editorial fixes.
-
The
allowpaymentrequest
attribute was removed due to deprecation by Payment Request API and HTML. Link