This specification defines a mechanism that allows developers to selectively enable and disable use of various browser features and APIs.

This document is outdated. Please refer to the explainer.

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:

  1. 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.
  2. 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.
  3. 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.

Examples

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

Feature-Policy: {"disable":["webrtc","geolocation"]}

Unless specified otherwise, the default target is "`\*`", which means that 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 whose origin is "`https://example.com`". It can do so by delivering the following HTTP response header to define a feature policy:

Feature-Policy: {"disable":["geolocation"], "target":["https://example.com"]}

The target is a list of one or more origins, which can include the applications origin and any third-party origin.

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

Feature-Policy: {"disable":["webrtc"], "target":["https://example.com"]},
        {"enable":["webrtc"], "target":["https://other.com"]}

Some features are disabled by default in embedded contexts. The enable policy allows the application to selectively enable such features for whitelisted origins.

FastCorp Inc. wants to disable use of synchronous `script` elements, synchronous `XMLHttpRequest`'s and use of `document.write` within their application. It can do so by delivering the following HTTP response header to define a feature policy:

Feature-Policy: {"disable":["sync-xhr","sync-script","docwrite"]}

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:

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 uses a whitelist approach which is impossible to extend without 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.

Framework

Policies

A feature policy may be applied to a [Window] or [WorkerGlobalScope] and consists of:

Directives

Each directive is a tuple consisting of:

The following sections define the set of known members in each JSON object describing the policy. Future versions of this document may define additional such members and user agents MUST ignore unknown members when parsing the object.

The target member

The OPTIONAL target member defines the scope in which the directive is enforced. The member's name is "`target`" and the recognized values are either an array of serialized origins which may contain the "`self`" keyword that refers to current global's origin, or the string "`\*`". If an unknown value is specified, or if no member named "`target`" is present in the object, the directive's target will be set to "`\*`".

The disable member

The OPTIONAL disable member defines the disable policy for the directive. The member's name is "`disable`" and the value is a list of ASCII strings.

The enable member

The OPTIONAL enable member defines the enable policy for the directive. The member's name is "`enable`" and the value is a list of ASCII strings. [response]

Delivery

`Feature-Policy` HTTP Header Field

The Feature-Policy HTTP header field can be used both in the [response] (server to client) and a [request] (client to server) to communicate the feature policy. In the former case, the server is communicating the desired policy that should be enforced by the client, and in the latter, the client is communicating the policy that it will enforce.

The header's value is represented by the following ABNF [[!RFC5234]]:

          Disable = 1#json-field-value
                    ; See Section 2 of [[HTTP-JFV]], and Section 2 of [[RFC7159]]
        

When the user agent receives a `Feature-Policy` header field, it MUST process and enforce the serialized policy as described in . When the user agent [performs a fetch][fetching algorithm], it MUST advertise the active feature policy as described in .

Process response policy

Given a [response] (response) and [global object] (global), this algorithm returns a feature policy.

  1. Abort these steps if the response’s [header list] does not contain a [header] whose [name] is "`Feature-Policy`".
  2. Let header be the [value] of the [header] in response’s [header list] whose name is "`Feature-Policy`".
  3. Let feature policy be the result of executing on header and global.

The `meta` element

A [Document] may deliver a policy via one or more HTML [meta] elements whose [http-equiv] attributes are an [ASCII case-insensitive] match for the string "`Feature-Policy`". For example:

The `meta` policy is processed as defined in and modifications to the [content][meta-content] attribute of a `meta` element after the element has been parsed MUST be ignored.

TODO: talk about effect of multiple policies

Process meta policy

This section extends HTML's `meta` [pragma directives].

Feature policy state (http-equiv="feature-policy")
  1. If the `meta` element is not a child of a `head` element, abort these steps.
  2. If the `meta` element is preceded by `link`, `script` or `style` elements, abort these steps.
  3. If the `meta` element has no [content][meta-content] attribute, or if that attribute's value is the empty string, then abort these steps.
  4. Let policy be the result of executing on the `meta` element's [content][meta-content] attribute's value and the current document's global.
  5. Enforce the policy policy.

Parse policy from value and global

Given a string (value) and [global object] (global) this algorithm will return a feature policy.

  1. Let list be the result of executing the algorithm defined in Section 4 of [[!HTTP-JFV]]. If that algorithm results in an error, abort these steps.
  2. Let policy be an empty list.
  3. For each item in list:
    1. Let target be an empty list.
    2. If item has a target member whose value is an array, then for each origin in the array:
      1. If origin is an [ASCII case-insensitive] match for "`self`", let result be the global's origin.
      2. Otherwise, let result be the result of executing the [URL parser] on origin
      3. If result is not `failure`, then append the [origin of result][origin-of-url] to target.
    3. If target is still an empty list, set target to "`\*`".
    4. Let disable be the result of executing on the item's disable member's value.
    5. Let enable be the result of executing on the item's enable member's value.
    6. Let tuple be a new directive tuple whose values are set as follows:
      "`target`"
      Set to target.
      "`disable`"
      Set to disable.
      "`enable`"
      Set to enable.
    7. Append tuple to policy.
  4. Return policy.

Features

This section defines features and their effect when applied via a directive as part of a feature policy.

The following table summarizes features defined by this specification, by their corresponding keywords. This table is non-normative; the actual definitions are given in the following sections.

Feature Enable policy Disable policy Brief description
top-level context nested context
cookie `\*` `\*` `null` Controls access to `document.cookie`.
domain `\*` `\*` `null` Controls access to `document.domain`.
docwrite `\*` `\*` `null` Controls access to `document.write`, `document.writeln`.
... ... ... ... ...
geolocation `self` `null` `null` Controls access to [Geolocation interface].
midi `self` `null` `null` Controls access to [requestMIDIAccess method].
notifications `self` `null` `null` Controls access to [Notification interface].
payment `self` `null` `null` Controls access to [PaymentRequest interface].
push `self` `null` `null` Controls access to [PushManager interface].
sync-script `\*` `\*` `null` Controls use of synchronous `script` elements.
sync-xhr `\*` `\*` `null` Controls access to synchronous `XMLHttpRequest` API.
usermedia `self` `null` `null` Controls access to [NavigatorUserMedia interface].
vibrate `self` `null` `null` Controls access to [vibrate method].
webrtc `\*` `\*` `null` Controls access to [RTCPeerConnection interface].

`cookie`

partial interface Document {
  [Feature=cookie] attribute USVString cookie;
};

The cookie keyword controls whether the [cookie attribute] is [exposed] for [current global object].

  1. The default enable policy is `\*` for [top-level browsing context], and `\*` for [nested browsing context].
  2. The default disable policy is `null`.

`domain`

partial interface Document {
  [Feature=domain] attribute USVString domain;
};

The domain keyword controls whether the [domain attribute] is [exposed] for [current global object].

  1. The default enable policy is `\*` for [top-level browsing context], and `\*` for [nested browsing context].
  2. The default disable policy is `null`.

`docwrite`

partial interface Document {
  [CEReactions, Feature=docwrite] void write(DOMString... text);
  [CEReactions, Feature=docwrite] void writeln(DOMString... text);
};

The docwrite keyword controls whether the [document.write] and [document.writeln] methods are [exposed] for [current global object].

  1. The default enable policy is `\*` for [top-level browsing context], and `\*` for [nested browsing context].
  2. The default disable policy is `null`.

`geolocation`

partial interface Navigator {
  [Feature=geolocation] readonly attribute Geolocation geolocation;
};

The geolocation keyword controls whether the [Geolocation interface] ([[!GEOLOCATION-API]]) is [exposed] for [current global object].

  1. The default enable policy is `self` for [top-level browsing context], and `null` for [nested browsing context].
  2. The default disable policy is `null`.

`midi`

partial interface Navigator {
  [Feature=midi] Promise<MIDIAccess> requestMIDIAccess (optional MIDIOptions options);
};

The midi keyword controls whether the [requestMIDIAccess method] ([[!WEBMIDI]]) is [exposed] for [current global object].

  1. The default enable policy is `self` for [top-level browsing context], and `null` for [nested browsing context].
  2. The default disable policy is `null`.

`notifications`

[Constructor(DOMString title, optional NotificationOptions options),
Feature=notifications]
interface Notification : EventTarget {};

The notifications keyword controls whether the [Notification interface] ([[!NOTIFICATIONS]]) is [exposed] for [current global object].

  1. The default enable policy is `self` for [top-level browsing context], and `null` for [nested browsing context].
  2. The default disable policy is `null`.

`payment`

[Constructor(sequence<PaymentMethodData> methodData, PaymentDetails details, optional PaymentOptions options),
 SecureContext, Feature=payment]
interface PaymentRequest : EventTarget {};

The payment keyword controls whether the [PaymentRequest interface] ([[!PAYMENT-REQUEST]]) is [exposed] for [current global object].

  1. The default enable policy is `self` for [top-level browsing context], and `null` for [nested browsing context].
  2. The default disable policy is `null`.

`push`

partial interface ServiceWorkerRegistration {
  [Feature=push] readonly attribute PushManager pushManager;
};

[Feature=push]
interface PushManager {};

The push keyword controls whether the [PushManager interface] ([[!PUSH-API]]) is [exposed] for [current global object].

  1. The default enable policy is `self` for [top-level browsing context], and `null` for [nested browsing context].
  2. The default disable policy is `null`.

`sync-script`

The sync-script keyword controls use of synchronous `script` elements, as defined in . When this feature is disabled, such scripts are ignored by the user agent.

Given the following header:

  Feature-Policy: {"disable":["sync-script"]}

The following HTML will not result in execution of `script1.js`, as it has neither a [`defer`] nor an [`async`] attribute. The remaining scripts will execute normally because they have their [non-blocking] flag set.

  <script src="/script1.js"></script>
  <script src="/script2.js" async></script>
  <script src="/script3.js" defer></script>
  <script>
    const scriptEl = document.createElement("script");
    scriptEl.src = "/script4.js";
    document.body.appendChild(scriptEl);
  </script>

`sync-xhr`

The sync-xhr keyword controls use of synchronous `XMLHttpRequest` API, as defined in . When [open() method](xhr-open) is called with async argument set to false, an `InvalidAccessError` except will be thrown.

Given the following header:

  Feature-Policy: {"disable":["sync-xhr"]}

The following JavaScript code will throw a `InvalidAccessError` exception:

  var xhr = new XMLHttpRequest();
  xhr.open("GET", "/foo", false);

`usermedia`

[Exposed=Window, NoInterfaceObject, Feature=usermedia]
interface NavigatorUserMedia {
    [SameObject] readonly attribute MediaDevices mediaDevices;
};

The usermedia keyword controls whether the [NavigatorUserMedia interface] ([[!MEDIACAPTURE-API]]) is [exposed] for [current global object].

  1. The default enable policy is `self` for [top-level browsing context], and `null` for [nested browsing context].
  2. The default disable policy is `null`.

`vibrate`

partial interface Navigator {
  [Feature=vibrate] boolean vibrate(VibratePattern pattern);
};

The vibrate keyword controls whether the [vibrate method] ([[!VIBRATION]]) is [exposed] for [current global object].

  1. The default enable policy is `self` for [top-level browsing context], and `null` for [nested browsing context].
  2. The default disable policy is `null`.

`webrtc`

[Constructor(optional RTCConfiguration configuration), Feature=webrtc]
interface RTCPeerConnection : EventTarget {};

The webrtc keyword controls whether the [RTCPeerConnection interface] ([[!WEBRTC]]) is [exposed] for [current global object].

  1. The default enable policy is `\*` for [top-level browsing context], and `\*` for [nested browsing context].
  2. The default disable policy is `null`.

Disable Policy

The disable policy allows a developer to turn off certain features for a Document or Worker.

Processing

Parse disable features

Given a list, this algorithm returns a list of features, which may be empty.

  1. Let valid-features be an empty list.
  2. If list is null or empty, return valid-features.
  3. For each item in list:
    1. Convert item to ASCII-lowercase.
    2. If item's string value is not one of the features, ignore item, and continue to the next item.
    3. Append item to valid-features.
  4. Return valid-features.

Enable Policy

The enable policy allows a developer to turn on certain features for a Document or Worker.

Processing

Parse enable features

Given a list, this algorithm returns a list of features, which may be empty.

  1. Let valid-features be an empty list.
  2. If list is null or empty, return valid-features.
  3. For each item in list:
    1. Convert item to ASCII-lowercase.
    2. TODO... should we merge/refactor this with disable parse?
    3. Append item to valid-features.
  4. Return valid-features.

Integrations

This document defines a set of algorithms which other specifications will use in order to implement the restrictions which Feature Policy defines. The integrations are outlined here for clarity, but those external documents are the normative references which ought to be consulted for detailed information.

Integration with HTML

  1. Document and WorkerGlobalScope objects have a Feature Policy List, which is either the empty set or a feature policy. This property is the empty set unless otherwise specified, and is populated via the algorithm that is called during the "Initialising a new Document object" and "Run a Worker" algorithms.
  2. A feature policy is enforced for a [global object] by inserting it into the [global object]'s Feature Policy list.
  3. Feature policy is enforced during processing of the meta element’s http-equiv.
  4. The "[prepare a script]" algorithm calls into algorithm to determine whether or not to execute a script, as follows:

    1. Add the following step before the current step 10 (which is the first of several "disabled" checks):
      1. If the `script` element's "`non-blocking`" flag is unset, the `script`'s type is "`classic`", and the algorithm returns "`Disabled`" when executed upon the `script` element's node document's global object, then abort these steps at this point. The script is not executed.
Monkey-patching! As soon as we know that this is the direction we wish to persuse, upstream all of this.

Initialize global's Feature Policy from response

Given a [response] (response) and a global object (global), this algorithm populates global's Feature Policy List

  1. If global is a `Window` and its `Document` has a parent browsing context or opener browsing context (context):
    1. Let document be the active document in context.
    2. For each directive in document's Feature Policy List:
      1. Add directive to global's `Document`'s Feature Policy List if any of the following are true:
        1. directive's target is "`\*`"
        2. directive's target is an array containing global's origin
        3. response's url's scheme is a local scheme
  2. If global is a `WorkerGlobalScope`:
    1. For each document in global's documents:
      1. For each directive in document's Feature Policy List:
        1. Add directive to global's Feature Policy List if either of the following are true:
          1. directive's target is "`\*`"
          2. directive's target is an array containing global's origin
          3. response's url's scheme is a local scheme
  3. Let policy be the result of executing on response and global.
  4. Enforce the policy policy.

Is feature disabled for global?

Given a string (feature) and a global object (global), this algorithm returns "`Disabled`" if feature should be considered disabled, and "`Enabled`" otherwise.

  1. Let policy be global's Feature Policy List
  2. If policy is empty, return "`Enabled`".
  3. For each directive in policy:
    1. If directive's disable contains feature:
      1. Return "`Disabled`".
  4. Return "`Enabled`".

Integration with Fetch

Set request policy

This monkey patches [fetching algorithm], by inserting the following steps after current step #4:

  1. If [request]'s [client] is not null and has a non-empty feature policy list, run the following steps:
    1. Let policy be the [current global object]'s feature policy list.
    2. Let serialized feature policy be the result of executing the [sender requirements] algorithm on policy, as defined in section 3 of [[!HTTP-JFV]].
    3. [Append](header-append) Feature-Policy/serialized feature policy to request's [header list].

Integration with XMLHttpRequest

The `open() method` calls into the algorithm to determine whether or not to throw, as follows:

  1. Add the following step after the current step 3:
    1. If async is false and the algorithm returns "`Disabled`" when executed upon "`sync-xhr`" and the document's global object, throw "`InvalidAccessError`" exception.

Integration with WebIDL

This section defines an extended attribute whose presence affects only the ECMAScript binding.

[Feature]

If the [Feature] [extended attribute] appears on an interface, partial interface, or an individual interface member, it indicates that the interface or interface member is subject to feature policy associated with the ECMAScript global environment's global object.

The [Feature] [extended attribute] must [take an identifier], which must be a [global name].

Whether a construct that the [Feature] [extended attribute] can be specified on is enabled by feature policy for global is defined as follows:

  1. If the [Feature] [extended attribute] is specified on the construct, then it is enabled by feature policy for global if the "is feature disabled for global?" algorithm returns "`Enabled`" when executed upon the extended attribute's argument and the ECMAScript global environment's global object.
  2. Otherwise, if the [Feature] [extended attribute] does not appear on a construct, then it is enabled by feature policy for global, depending on the type of construct:
    1. **Interface**: the interface or dictionary is implicity "`Enabled`" by feature policy.
    2. **Partial interface**: the partial interface is enabled by feature policy for global if and only if the original interface definition is.
    3. **Interface member**: the interface member is enabled by feature policy for global if and only if the interface or partial interface the member is declared on is.

Whether a construct is enabled by feature policy for global influences whether it is [exposed] in a given ECMAScript global environment.

IANA Considerations

The permanent message header field registry should be updated with the following registration [[!RFC3864]]:

Header field name
Feature-Policy
Applicable protocol
http
Status
standard
Author/Change controller
W3C
Specification document
Feature Policy API

Privacy and Security

TODO

[sandbox attribute]: https://html.spec.whatwg.org/multipage/the-iframe-element.html#attr-iframe-sandbox [sandbox directive]: https://www.w3.org/TR/2014/WD-CSP11-20140211/#sandbox [window]: https://www.w3.org/TR/html5/browsers.html#dom-window [workerglobalscope]: https://html.spec.whatwg.org/multipage/workers.html#workerglobalscope [response]: https://fetch.spec.whatwg.org/#concept-response [request]: https://fetch.spec.whatwg.org/#concept-request [HTTPS state]: https://fetch.spec.whatwg.org/#concept-response-https-state [origin]: https://url.spec.whatwg.org/#concept-url-origin [url]: https://fetch.spec.whatwg.org/#concept-response-url [potentially trustworthy]: https://w3c.github.io/webappsec-secure-contexts/#is-origin-trustworthy [header list]: https://fetch.spec.whatwg.org/#concept-response-header-list [header]: https://fetch.spec.whatwg.org/#concept-header [name]: https://fetch.spec.whatwg.org/#concept-header-name [value]: https://fetch.spec.whatwg.org/#concept-header-value [xhr-open]: https://xhr.spec.whatwg.org/#the-open()-method [docwrite method]: https://html.spec.whatwg.org/#dom-document-write [async]: https://html.spec.whatwg.org/#attr-script-async [defer]: https://html.spec.whatwg.org/#attr-script-defer [prepare a script]: https://html.spec.whatwg.org/#prepare-a-script [non-blocking]: https://html.spec.whatwg.org/#non-blocking [header-append]: https://fetch.spec.whatwg.org/#concept-header-list-append [header-list]: https://fetch.spec.whatwg.org/#concept-request-header-list [fetching algorithm]: https://fetch.spec.whatwg.org/#fetching [global object]: https://html.spec.whatwg.org/multipage/webappapis.html#global-object [current global object]: https://html.spec.whatwg.org/#current-global-object [client]: https://fetch.spec.whatwg.org/#concept-request-client [sender requirements]: https://greenbytes.de/tech/webdav/draft-ietf-httpbis-jfv-02.html#rfc.section.3 [non-blocking]: https://html.spec.whatwg.org/#non-blocking [URL parser]: https://url.spec.whatwg.org/#concept-url-parser [origin-of-url]: https://url.spec.whatwg.org/#concept-url-origin [ascii case-insensitive]: https://html.spec.whatwg.org/multipage/infrastructure.html#ascii-case-insensitive [document]: https://html.spec.whatwg.org/multipage/dom.html#document [meta]: https://html.spec.whatwg.org/#the-meta-element [http-equiv]: https://html.spec.whatwg.org/#attr-meta-http-equiv [meta-content]: https://html.spec.whatwg.org/#attr-meta-content [pragma directives]: https://html.spec.whatwg.org/#attr-meta-http-equiv-content-security-policy [extended attribute]: https://heycam.github.io/webidl/#dfn-extended-attribute [take an identifier]: https://heycam.github.io/webidl/#dfn-xattr-identifier [global name]: https://heycam.github.io/webidl/#dfn-global-name [exposed]: https://heycam.github.io/webidl/#dfn-exposed [cookie attribute]: https://html.spec.whatwg.org/#dom-document-cookie [domain attribute]: https://html.spec.whatwg.org/#dom-document-domain [top-level browsing context]: https://html.spec.whatwg.org/#top-level-browsing-context [nested browsing context]: https://html.spec.whatwg.org/#nested-browsing-context [document.write]: https://html.spec.whatwg.org/#dom-document-write [document.writeln]: https://html.spec.whatwg.org/#dom-document-writeln [Geolocation interface]: https://www.w3.org/TR/geolocation-API/#geolocation_interface [NavigatorUserMedia interface]: https://w3c.github.io/mediacapture-main/#navigatorusermedia [RTCPeerConnection interface]: http://w3c.github.io/webrtc-pc/#rtcpeerconnection-interface [Notification interface]: https://www.w3.org/TR/notifications/#notification [PaymentRequest interface]: https://www.w3.org/TR/payment-request/#paymentrequest-interface [PushManager interface]: https://w3c.github.io/push-api/#idl-def-PushManager [requestMIDIAccess method]: http://webaudio.github.io/web-midi-api/#requestMIDIAccess [vibrate method]: https://w3c.github.io/vibration/#idl-def-navigator-vibrate(vibratepattern)