Stop accidental and nefarious use of device features
Feature Policy
Preliminaries
Keep your browser on your side. Prevent apps from accidentally gaining access to unauthorized mobile device features. Stop bad actors from elevating privileges without your consent.
Modern communication and computing devices — such as cellphones, tablets, and laptops — can access APIs that are potentially intrusive. Cameras, microphones, and GPS trackers are examples. Owners already have the ability to control which apps have access to these, but sometimes a well-respected app may be granted advanced permissions, which could accidentally be misused (if the developers aren't diligent), by a third-party plugin.
To help keep your app working the way you originally intended, you can create a policy that specifies which APIs you need and which sources within your codebase are allowed to use them. This policy is then registered with the browser, and enforced on your behalf by the browser for your website's documents. This policy is not able to relax any restriction the device's owner may have already set. It can only tighten the restriction. With this enforcement mechanism in place, you can gain confidence that new features implemented by third parties aren't going to spoil your reputation.
You enlist the browser's support in enforcing your policy by establishing rules that govern how device APIs are allowed to access the features it needs. Features are things like camera, microphone, USB, magnetometer, accelerometer, etc. Rules declare which sources are allowed to use those features, and where those sources are located.
The set of rules that your website agrees to is published as a policy, and that policy is shared with the browser. This is done with the "feature-policy" response header. It is sent by the server with the response to a browser request for a document, that is, it is sent when the response has a content-type
of text/html
or application/xhtml+xml
.
A policy can be as simple as a single rule with a single policy declaration, for example, geolocation 'self'
.
In this example geolocation
is a feature rule, and 'self'
is a policy declaration.
A policy can, and often does, include several rules. Furthermore, a policy declaration can include multiple allowable sources. Because of this, a full policy can be complex and intimidating to parse visually. The Read Write Serve configuration file, provides a structured way to declare the parts of a full policy. This makes it visually cleaner for humans to parse. Internally, the server converts this structured declaration into a single comma-separated string, suitable for sending in a response header.
Rules
Some policy rules are related to hardware components, as already demonstrated. Other rules are related to best practices. For example, the former use of synchronous XMLHttpRequest is now discouraged, and a rule could be added to explicitly trap any such attempt to do that.
The feature-policy
header is experimental and is governed by a draft specification at this time (June 2019). Only a few features are presently available. Others are coded and ready for testing in Chrome Canary. Still more, are slated for the future. See Feature Policy Demos for what's currently available.
Currently implemented
Features that are available for policy usage in Chrome 75.
Feature | Description |
---|---|
autoplay | Allows the autoplay attribute on videos within same-origin iframes |
geolocation | Allows/disables the use of the Geolocation API |
picture-in-picture | Allows the usage of Picture-in-Picture in cross-origin iframes |
vertical-scroll | Controls whether embedded content can interfere with vertical scrolling |
sync-xhr | Disallows the use of synchronous XMLHttpRequests |
sync-script | Prevents synchronous scripts from executing |
oversized-images | Ensures intrinsic size of images are not more than X times larger than their container size |
unoptimized-lossy-images | Requires size of JPG file, in bytes, to be no more than X times bigger than its visible size (width * height) |
unoptimized-lossless-images | Requires size of WEBP file, in bytes, to be no more than X times bigger than its visible size (width * height) |
unoptimized-lossless-images-strict | Requires size of WEBP file, in bytes, to be no more than X times bigger than its visible size (width * height) |
unsized-media | Sets a default size of 300x150 if dimensions aren't specified |
Available in Chrome Canary
Features that are available for policy usage when using a Chrome experimental flag.
Feature | Description |
---|---|
animations | Restricts the set of CSS properties which can be animated to opacity, transform, and filter |
Slated for the Future
Features that are announced, but not yet implemented
Feature |
---|
accelerometer |
ambient-light-sensor |
camera |
document-domain |
document-write |
downloads-without-user-activation |
encrypted-media |
focus-without-user-activation |
font-display-late-swap |
forms |
fullscreen |
gyroscope |
hid |
idle-detection |
layout-animations |
loading-frame-default-eager |
magnetometer |
microphone |
midi |
modals |
orientation-lock |
payment |
pointer-lock |
popups |
presentation |
scripts |
serial |
speaker |
top-navigation |
usb |
vr |
wake-lock |
Policy declarations
The features just described, are paired with a policy declaration. A policy declaration consists of one or more allowable sources, which are described here.
Allowable source | Description |
---|---|
'*' | This is used, by itself, when the feature is allowed by the current document and all child browsing contexts, including cross-domain contexts. (The enclosing APOSTROPHES are necessary.) |
'self' | This is used, by itself or in combination with others, when the feature is allowed by the current document. This is the most common allowable source. It simply means that the feature is allowed for the source document itself, plus any same-domain child browsing contexts coming from the same location as the document (same protocol + hostname + port). (The enclosing APOSTROPHES are necessary.) |
protocol://hostname:port | This is used, by itself or in combination with 'self', to allow sources from the specified origin to access the feature. The protocol may be https or http . The hostname may be any resolvable DNS hostname (or an IP address), and may include a wildcard prefix to allow access from any subdomain. The port may be included, but is optional. |
'none' | This is used, by itself, when no sources are allowed, effectively blocking all usage of the feature associated with the rule. (The enclosing APOSTROPHES are necessary.) |
report to
The 'feature-policy' header does not have a report-to
mechanism. Enforcement happens on the owner's device, without feedback to the server. If a third-party plugin attempts to use a disallowed feature, the browser will silently block it.
Configuration
The feature-policy
section is configured subordinate to the policies
section. It comprises one or more rules, each as a separate line item. Each line item starts with the name of the feature, followed by a space-separated list of allowable sources.
To be effective, the policies
module must be turned on
.
EBNF
SP | ::= | U+20 |
CR | ::= | U+0D |
QUOTATION-MARK | ::= | U+22 |
APOSTROPHE | ::= | U+27 |
ASTERISK | ::= | U+2A |
COMMA | ::= | U+2C |
HYPHEN | ::= | U+2D |
FULL-STOP | ::= | U+2E |
EQUALS-SIGN | ::= | U+3D |
LEFT-CURLY-BRACKET | ::= | U+7B |
RIGHT-CURLY-BRACKET | ::= | U+7D |
allowable sources | ||
---|---|---|
star-keyword | ::= | APOSTROPHE '*' APOSTROPHE |
self-keyword | ::= | APOSTROPHE 'self' APOSTROPHE |
none-keyword | ::= | APOSTROPHE 'none' APOSTROPHE |
origin-hostname | ::= | (ALPHA | DIGIT | FULL-STOP | HYPHEN)* |
wildcard-hostname | ::= | ASTERISK origin-hostname |
feature rules | ||
feature | ::= | ('unoptimized-lossy-images' | 'unoptimized-lossless-images' | 'unoptimized-lossless-images-strict' | 'unsized-media' | 'autoplay' | 'geolocation' | 'picture-in-picture' | 'vertical-scroll' | 'lazyload' | 'sync-xhr' | 'sync-script')* SP |
feature-rule | ::= | feature SP (star-keyword | self-keyword | none-keyword | origin-hostname | wildcard-hostname) CR |
sections | ||
feature-policy | ::= | 'feature-policy' SP LEFT-CURLY-BRACKET CR feature-rule* RIGHT-CURLY-BRACKET CR |
policy-configs | ::= | referrer-policy† | content-security-policy† | feature-policy | network-error-logging† | report-to† |
policies-section | ::= | 'policies' SP LEFT-CURLY-BRACKET CR policy-configs* RIGHT-CURLY-BRACKET CR |
† These are defined in separate notes
Cookbook
Example 1: Allow any source to perform synchronous XHR
server {
modules {
policies on
}
policies {
feature-policy {
sync-xhr '*'
}
}
}
Example 2: Allow same-domain sources to use Picture-in-Picture
server {
modules {
policies on
}
policies {
feature-policy {
picture-in-picture 'self'
}
}
}
Example 3: Allow AppSpot to use geolocation
server {
modules {
policies on
}
policies {
feature-policy {
geolocation 'self' https://google-developers.appspot.com
}
}
}
Example 4: Disallow video autoplay
server {
modules {
policies on
}
policies {
feature-policy {
autoplay 'none'
}
}
}
Example 5: Multiple rules
server {
modules {
policies on
}
policies {
feature-policy {
sync-xhr '*'
picture-in-picture 'self'
geolocation 'self' https://google-developers.appspot.com
autoplay 'none'
}intrinsic
}
}
Review
Key points to remember:
- The policies module must be on to enable the feature-policy.
- The
feature-policy
response header is only sent when an HTML document is requested. - Policies further tighten browser access to features, they never relax the owner's own settings.