Implements default Permissions-Policy header (#158514)

Closes #154252

## Summary

This PR implements a default [permissions policy
header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy)
for Kibana. It takes into consideration only the directives that are
_not_ still in development/pre-release. These directives are:
 - camera
 - display-capture
 - fullscreen
 - geolocation
 - microphone
 - web-share

All directives above are set to an empty or "none" allow list, with the
exception of `fullscreen`. The default permissions policy for Kibana
will be: `camera=(), display-capture=(), fullscreen=(self),
geolocation=(), microphone=(), web-share=()`.

The `display-capture` directive only affects access to the [Screen
capture
API](https://developer.mozilla.org/en-US/docs/Web/API/Screen_Capture_API),
whereas our reporting utilities rely on a headless Chrome feature.
FullyStory also does not appear to rely on capturing the screen, but
rather on [capturing the DOM and
CSS](3600206230-Does-FullStory-work-with-my-complex-site-)
to reproduce the screen and user stories. We have confirmed with
FullStory support that they do not use the Screen capture API
(`getDisplayMedia()`).

The `fullscreen` directive affects access to the
[element.requestFullscreen
API](https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullscreen).
Our fullscreen view for Dashboards and visualizations appear to be
scoped to the Kibana application and not the browser or system, but
there is one use of `requestFullscreen` in the synthetics plugin's
`grid_group_item`, hence the default setting of 'self' here.

## Testing
Due to screen capture reports (PNG & PDF) and fullscreen modes working
with the configuration defined above, I wanted to double-check the
header was working, so I tested both camera and microphone access. I did
this by adding some code into our team's user management screen that
would attempt to access both the camera and microphone. I could confirm
that with the permissions policy header (as defined), no access prompts
would appear for either resource. When I removed the directives for the
camera and microphone from the permissions policy header, prompts
appeared in the browser (Chrome) to approve access to the camera and
microphone.

### Manual Test:
1. Start Elasticsearch and Kibana from this PR
2. Sign into Kibana and open your browser's dev tools
3. In the network tab, inspect one of the requests for localhost
4. In the Headers tab, verify the permissions-policy header is present
with the new default value defined above, `camera=(),
display-capture=(), fullscreen=(self), geolocation=(), microphone=(),
web-share=()`
5. Edit the kibana.yml file, add
`server.securityResponseHeaders.permissionsPolicy: camera=(self)`
6. Refresh Kibana in the browser, verify the permissions-policy header
is present with the value set in kibana.yml in step 5
7. Edit the kibana.yml file, add
`server.securityResponseHeaders.permissionsPolicy: null`
8. Refresh Kibana in the browser, verify the permissions-policy header
is no longer present

## Release Notes:
Security
Adds default Permissions-Policy header including all non-experimental
directives [#158514](https://github.com/elastic/kibana/pull/158514)

---------

Co-authored-by: James Rodewig <james.rodewig@elastic.co>
This commit is contained in:
Jeramy Soucy 2023-06-07 19:48:44 +02:00 committed by GitHub
parent ff5b71c10d
commit dd3193c88e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 11 additions and 7 deletions

View file

@ -409,9 +409,11 @@ responses to the client from the {kib} server, and specifies what value is used.
`unsafe-url`, or `null`. To disable, set to `null`. *Default:* `"no-referrer-when-downgrade"`
[[server-securityResponseHeaders-permissionsPolicy]] `server.securityResponseHeaders.permissionsPolicy`::
experimental[] Controls whether the https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy[`Permissions-Policy`] header
experimental[] Controls whether the https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy[`Permissions-Policy`] header
is used in all responses to the client from the {kib} server, and specifies what value is used. Allowed values are any text value or `null`.
To disable, set to `null`. *Default:* `null`
Refer to the https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy[`Permissions-Policy` documentation] for defined
directives, values, and text format. To disable, set to `null`.
*Default:* `camera=(), display-capture=(), fullscreen=(self), geolocation=(), microphone=(), web-share=()`
[[server-securityResponseHeaders-disableEmbedding]]`server.securityResponseHeaders.disableEmbedding`::
Controls whether the https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy[`Content-Security-Policy`] and

View file

@ -82,7 +82,7 @@ Object {
"securityResponseHeaders": Object {
"crossOriginOpenerPolicy": "same-origin",
"disableEmbedding": false,
"permissionsPolicy": null,
"permissionsPolicy": "camera=(), display-capture=(), fullscreen=(self), geolocation=(), microphone=(), web-share=()",
"referrerPolicy": "no-referrer-when-downgrade",
"strictTransportSecurity": null,
"xContentTypeOptions": "nosniff",

View file

@ -19,6 +19,7 @@ describe('parseRawSecurityResponseHeadersConfig', () => {
expect(result.securityResponseHeaders).toMatchInlineSnapshot(`
Object {
"Cross-Origin-Opener-Policy": "same-origin",
"Permissions-Policy": "camera=(), display-capture=(), fullscreen=(self), geolocation=(), microphone=(), web-share=()",
"Referrer-Policy": "no-referrer-when-downgrade",
"X-Content-Type-Options": "nosniff",
}

View file

@ -33,9 +33,10 @@ export const securityResponseHeadersSchema = schema.object({
{ defaultValue: 'no-referrer-when-downgrade' }
),
permissionsPolicy: schema.oneOf([schema.string(), schema.literal(null)], {
// See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy
// Note: Feature-Policy is superseded by Permissions-Policy; the link above is temporary until MDN releases an updated page
defaultValue: null,
// See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy
// Note: this currently lists all non-experimental permissions, as of May 2023
defaultValue:
'camera=(), display-capture=(), fullscreen=(self), geolocation=(), microphone=(), web-share=()',
}),
disableEmbedding: schema.boolean({ defaultValue: false }), // is used to control X-Frame-Options and CSP headers
crossOriginOpenerPolicy: schema.oneOf(

View file

@ -310,7 +310,7 @@ describe('CoreUsageDataService', () => {
"securityResponseHeaders": Object {
"crossOriginOpenerPolicy": "same-origin",
"disableEmbedding": false,
"permissionsPolicyConfigured": false,
"permissionsPolicyConfigured": true,
"referrerPolicy": "no-referrer-when-downgrade",
"strictTransportSecurity": "NULL",
"xContentTypeOptions": "nosniff",