Security Tip: Do You Have a Permissions Policy?

[Tip #85] What browser features do you have enabled on your site, and what can an XSS attack do if you don't disable them?

Security Tip: Do You Have a Permissions Policy?

The Permissions Policy is a header (Permissions-Policy) and iframe attribute (<iframe allow="...">) that defines what browser features, such as the camera, geolocation, microphone, accelerometer, etc, can be used on the current page or within the frame. It is similar to a Content Security Policy, but applies to browser features, rather than resources within the page.

It was primarily designed for iframes via the allow attribute, where some browser features are disabled within frames by default, and there was a need to control what features embedded pages were allowed to use (and what they weren't), and was expanded out to include the Permissions-Policy header, to work on the top level page too.

The secondary benefit to a Permissions Policy is to limit the impact of XSS attacks. By disabling browser features your site doesn't need, any attackers who successfully exploit XSS on your site won't be able to do things like turn on your user's microphone or camera, etc. It may also help limit creepy trackers your marketing department insists you install!

The easiest way to get started is to head over to the Permissions Policy HTTP Header Generator at https://permissionspolicy.com/.

You can select the features you need enabled and it will give you the full policy:

Permissions Policy HTTP Header Generator with an example policy loaded.
Permissions-Policy: accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(self), camera=(), cross-origin-isolated=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=*, geolocation=(self), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), navigation-override=(), payment=("https://shop.example.com"), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=()

Throw that in your app headers, and you'll have a permissions policy.

Is there a downside?

Just like a CSP, you need to ensure your site doesn't need the features you disable. Also note that browser extensions can rely on these features and be blocked by the policy. I had trouble with a screen recording extension on one site, because the Permissions Policy blocked the camera, etc.

Wait, isn't this the same as the Feature-Policy header?

Yep! The Permissions-Policy header used to be called Feature-Policy, so you may still see references to that in older documentation. You should use Permissions-Policy now, and note the syntax changed slightly too.


If you haven't seen it yet, check out my last In Depth article where I covered the Passive Scans I run during my Laravel Security Audits and Penetration Tests:

In Depth: Pentesting Laravel part 1 - Passive Scans
[In Depth #27] Let me walk you through my process of conducting a Laravel Security Audit and Penetration Test, starting with the passive scans that usually find a lot of low-hanging fruit!

If you've made it this far, please share this Security Tip and Securing Laravel with your Laravel friends, colleagues, and enemies! The more folks we have learning about security, the more secure code will be written, and the safer the whole community and our users will be. Also, if you tag me I'll give it a retweet, and you can find all my socials on Pinkary.