What is Feature Policy?
Feature Policy allows us to control the behavior of certain web APIs and features in the browser. We can specify which APIs are to be disabled or enabled for a given list of origins.
Feature Policy provides two ways to do this:
- Feature-Policy HTTP header
Feature-Policy: camera 'none'
Feature-Policy: payment 'self' 'https://example.com'allowattribute on iframes (Not supported by this change)
<iframe src='https://example.com' allow='fullscreen'></iframe>
<iframe src='https://example.com' allow='geolocation *'></iframe>Google Dev Blog, has an in-depth article explaining this functionality in detail.
Why should we use it?
It allows us to enforce similar UX throughout the application by enforcing the policies. In case a third party attempts an unexpected action, the browser will adhere to the policies provided by us and maintain the intended UX.
Policies are a contract between developer and browser. They inform the browser about what the developer’s intent is and thus, help keep us honest when our app tries to go off the rails and do something bad. If the site or embedded third-party content attempts to violate any of the developer’s preselected rules, the browser overrides the behavior with better UX or blocks the API altogether.
Let’s configure it in rails
Rails 6.1 adds a DSL for configuring the Feature-Policy HTTP header. The DSL is almost identical to that of configuring Content Security Policy.
We can define a policy with global scope in an initializer:
# config/initializers/feature_policy.rb
Rails.application.config.feature_policy do |f|
f.camera :none
f.geolocation :self, 'https://example.com'
f.payment :self, '*'
endLet us see what is the value of the Feature-Policy response header in this case.
Feature-Policy Header value
This example would do the following:
- Usage of
cameraAPI will be disallowed for all browsing contexts. - Usage of
geolocationAPI will be disallowed for all browsing contexts except the page’s own origin andhttps://example.com. - Usage of
paymentAPI will be allowed for all browsing contexts.
We can also override the global policy within a controller:
# app/controllers/profiles_controller.rb
class ProfilesController < ApplicationController
def edit
feature_policy do |f|
f.camera :self
end
end
endThis example would disallow usage of camera API for all browsing contexts(origin and third party extension)
except the page’s own origin but only on ProfilesController#edit.
This behavior will override any policies written in the global policy for the camera feature.
Let’s see this in action
We will first set a Feature Policy in the initializer like the example above.
# config/initializers/feature_policy.rb
Rails.application.config.feature_policy do |f|
f.geolocation :none
endNext up, we open up a page in our application where we have a map.
The map shows the user’s current location.
This is done via a script, which uses geolocation API.
Let’s see what happens.
Geolocation disabled
The script was not able to access the geolocation API because of the policy set above.
Here’s a more detailed reason why this happened.
Without Feature Policy
Console without Feature Policy
With Feature Policy
Console with Feature Policy
The Feature Policy we enforced on the browser, didn’t let the script access the geolocation API.
Can we use it yet?
See caniuse.com for the latest details on browser support.
As of today, the HTTP Feature-Policy header is supported by Chrome, Edge, Opera, and some mobile browsers.
