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 feature policy mechanism that addresses the
above use cases.

2. Examples

SecureCorp Inc. wants to disable use of Vibration and Geolocation APIs
within their application. It can do so by delivering the following HTTP
response header to define a feature policy:

By specifying the "'none'"keyword for the origin list, the
specified features will be disabled for all browsing contexts, regardless of
their origin.

SecureCorp Inc. wants to disable use of Geolocation API within all
browsing contexts except for its own origin and those whose origin is
"https://example.com". It can do so by delivering the
following HTTP response header to define a feature policy:

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.

SecureCorp Inc. is hosting an application on
"https://example.com" and wants to disable camera and
microphone input on its own origin but enable it for a specific embedee
("https://other.com"). It can do so by delivering the
following HTTP response header to define a feature policy:

Iframe attributes can selectively enable features in certain frames, and
not in others, even if those contain documents from the same origin.

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.

Feature 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 feature policy.

For brevity, policy-controlled features will often be
referred to in this document simply as "Features". Unless otherwise
indicated, the term "feature" refers to policy-controlled features.
Other specifications, defining such features, should use the longer term to
avoid any ambiguity.

This spec currently only deals with features defined in
Documents. We should figure out how to word this to include the possibility
of features and feature policies in Workers and Worklets as well.

Each policy-controlled feature has a default allowlist,
which defines whether that feature is available in documents in top-level
browsing contexts, and how access to that feature is inherited in nested
browsing contexts.

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.

Each document in a frame tree inherits a set of policies from its parent
frame, or in the case of the top-level document, 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.

4.8. Allowlists

The keywords '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 allowlistmatches an origin origin, run these steps:

4.9. 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 browsing context, and also
whether access to the feature is automatically delegated to documents in
nested browsing contexts.

The feature is allowed in documents in top-level browsing contexts by
default, and when allowed, is allowed by default to documents in nested
browsing contexts.

'self'

The feature is allowed in documents in top-level browsing contexts by
default, and when allowed, is allowed by default to same-origin domain
documents in nested browsing contexts, but is disallowed by default in
cross-origin documents in nested browsing contexts.

'none'

The feature is disallowed in documents in top-level browsing contexts
by default, and is also disallowed by default to documents in nested
browsing contexts.

5. Feature Policy Serialization

5.1. ASCII serialization

Policy Directives are represented in HTTP headers and in HTML
attributes as ASCII text.

serialized-origin is the serialization of an origin. However, the code points U+0027 ('),
U+0021 (*), U+002C (,) and U+003B (;) MUST NOT appear in the serialization.
If they are required, they must be percent-encoded as "%27", "%2A",
"%2C" or "%3B", respectively.

The string "'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 feature policy.

6. Delivery

6.1. Feature-Policy HTTP Header
Field

The `Feature-Policy` HTTP
header field can be used in the response (server to client) to
communicate the feature policy that should be enforced by the
client.

This is different from the behaviour of <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.

This is different from the behaviour of <iframe
allow="payment">, and is for compatibility with existing uses
of allowpaymentrequest. If allow="payment" and allowpaymentrequest are both present on an iframe
element, then the more restrictive allowlist of allow="payment" will be used.

This is different from the behaviour of <iframe
allow="camera; microphone">, and is for compatibility with
existing uses of allowusermedia. If allow="camera;
microphone" and allowusermedia are both present on
an iframe element, then the more restrictive allowlist of allow="camera; microphone" will be used. Similarly, if only
one of allow="camera" or allow="microphone" is
present, then the more restrictive allowlist will be used for that
feature, while the other will use the less restrictive *.

7. Policy Introspection from Scripts

The introspection API described in this section is early in development, and
is likely to change — possibly significantly — before it is
finalized. Web developers are encouraged to experiment with using the API,
and provide
feedback, but should be aware that it may change or be removed
completely.

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 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 Policy object which can be used to
inspect the feature policies which apply to them.

The name policy is intentionally broad: the Policy object is intended
to be extendable to other kinds of policies, such as Content Security
Policy, rather than being exclusively dedicated to Feature Policy. Future
methods added to the object should be named appropriately, to indicate the
kinds of policies they refer to.

7.1.1. Document policies

To retreive the currently effective policy, use document.policy(). This returns a policy 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 allowed features in the current document, or

get the allowlist for a given feature in the current document.

<!doctype html>
<script>
let policy = document.policy;
// This will be true if this document can use WebUSB
let can_use_usb = policy.allowsFeature('usb');
// True if a new frame at https://example.com will be allowed to use WebVR
if (policy.allowsFeature('vr', '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.
let allowed_payment_origins = policy.getAllowlistForFeature('payment');
</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 nested browsing context in that case could leak
information about the behaviour of a cross-origin document.

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>
let iframe_element = document.getElementById("frame");
let iframe_policy = iframe_element.policy;
// This will be false, as the URL listed in the src attribute is not allowed
// by policy to use fullscreen.
let is_fullscreen_allowed_in_frame = iframe_policy.allowsFeature('fullscreen');
let new_frame = document.createElement('iframe');
new_frame.allow = 'syncxhr';
// This will be true, as the iframe is allowed to use syncxhr at whatever URL is
// mentioned in its src attribute, even though that attribute is not yet set.
let is_syncxhr_allowed = new_frame.policy.allowsFeature('syncxhr');
</script>

The observable policy for any Node is a feature policy,
which contains the information about the policy in the browsing context
represented by that Node which is visible from the current browsing context.

To get the observable policy for a Document document, return document’s feature policy.

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

Feature policy violation reports indicate that some behavior of
the Document has violated a feature policy. It is up to each
individual feature policy to define/determine when a violation of that policy has
occurred.

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 feature 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).

Note: There is currently no mechanism in place for enabling report-only
mode, so disposition will always be
set to "enforce".

9.5. Process feature policy
attributes

Let container policy be the result of running Parse policy directive on the value of element’s allow attribute, with container
origin set to the origin of element’s node document,
and target origin set to element’s declared
origin.

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.

11. 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.

11.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.

11.2. Unanticipated behavior changes

Feature policy 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:

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 feature policy which is
currently enforced, and adjust behaviour or user interface accordingly.

Authors integrating their features with Feature 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.

11.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.

Conformance

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology.
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL”
in the normative parts of this document
are to be interpreted as described in RFC 2119.
However, for readability,
these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative
except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example”
or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note”
and are set apart from the normative text with class="note", like this: