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.

Stop accidental and nefarious use of device features