Permission Delegation To Embedded Web Applications

Editor’s Draft,

This version:
https://github.com/noncombatant/permission-delegation-api
Feedback:
public-webappsec@w3.org with subject line “[permission-delegation] … message topic …
Issue Tracking:
GitHub
Editors:
Raymes Khoury (Google Inc.)
Chris Palmer (Google Inc.)
Participate:
We are on Github.
File a bug.
Commit history.
Mailing list.
Implementation status:
Blink/Chromium
Gecko

Abstract

This document proposes a recommendation for how UAs should manage access to permissions in applications built from cross-origin components. We recommend that UAs only allow permissions to be granted to embedded applications via explicit delegation from the embedding application.

We describe a web platform API for delegating permissions to embedded applications. This API allows a web application to explicitly delegate and un-delegate permissions that it holds to cross-origin embedded applications. It also allows a web application to query the status of delegation to an embedded application.

Status of this document

This is a public copy of the editors’ draft. It is provided for discussion only and may change at any moment. Its publication here does not imply endorsement of its contents by W3C. Don’t cite this document other than as work in progress.

Changes to this document may be tracked at https://github.com/w3c/webappsec.

The (archived) public mailing list public-webappsec@w3.org (see instructions) is preferred for discussion of this specification. When sending e-mail, please put the text “permission-delegation” in the subject, preferably like this: “[permission-delegation] …summary of comment…

This document was produced by the Web Application Security Working Group.

This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

This document is governed by the 1 September 2015 W3C Process Document.

1. Definitions

A powerful feature#powerful-featureReferenced in:3. Delegating Permissions is a web platform feature or API that allows an origin to have access to information the user may consider security- or privacy-sensitive, or access to pwoerful sensors on the platform the UA runs on, such as the camera or microphone.

A permission, generally, is an affordance in the UA to allow, deny, throttle, or otherwise regulate access to a powerful feature that the user, through the UA, may grant to the web origin. Examples of powerful features include [geolocation-API] and the getUserMedia API from [webrtc].

An embedder is a Document that includes a nested browsing context. An embedee is a Document contained within the nested browsing context of an embedder. Typically, an embedder would include an embedee using an iframe element. A top-level embedder is an embedder loaded in a top-level browsing context.

An embedder can delegate permissions it holds to its embedee(s), thus allowing the embedee to use the powerful feature to which the permission grants access. Similarly, an embedder can undelegate (revoke) a permission from an embedee.

Applications built from an embedder and 1 or more embedees from different origins are composed applications.

2. Background And Motivations

Web applications are able to request permissions, such as geolocation, using various APIs on the web platform. Many UAs will defer the decision to the user, prompting the user to make a decision about the permission (e.g. Allow, Deny, satisfy the request using a particular input source, et c.). Thus the user has some control over the capabilities they grant to a requesting origin. Many UAs will persist the user’s decisions, so that the user will not have to make a decision for subsequent access requests.

Web applications are composable: one web application (the embedder) can embed others (embedees) by using the <iframe> HTML tag. If a cross-origin embedee request permissions, it can be problematic from the perspective of both the user and the embedder. There are 4 reasons for this:

  1. People don’t have a good understanding of permission requests from embedees. There is often no UI in the UA indicating that embedees are present or what their origin is. They may even be invisible on a page. It is not easy to communicate the concept of composed applications to people using the web. The results of a user study [iframe-permissions-study] showed that participants were generally confused about who they were granting access to when a permission request came from an embedee.
  2. It’s unclear how a UA should persist the permission decisions people make for composed applications. Different UAs persist people’s decisions about embedees in different ways. Some UAs associate the permission grant to the combination of the embedder’s origin and the embedee’s origin, such that the UA recalls the decision about the embedee’s permissions only when embedded in that same embedder. Other UAs associate the grant only to the requesting origin, regardless of whether and where it is embedded. Either mechanism is likely to violate people’s expectations, at least some of the time. The inconsistency across — and even within — UAs further exacerbates the problem.
  3. It is difficult to build a permission management UI that people can understand and use effectively. This is particularly true if UAs adhere permission grants to a combination of the embedder’s and embedees’ origins. UI surfaces for revocation and auditing must attempt to display multiple origins in a way that people can understand.
  4. Embedders currently have no way to regulate their embedees’ use of powerful features. Embedees can thus behave in ways that reflect badly on the embedder.

To address these issues, we recommend that UAs require embedders to explicitly delegate permissions to embedees, rather than allow embeddees to unilaterally use or request to permissions. People would only ever be required to make permission decisions about the apparent origin of the application: that of the top-level embedder. The benefits of this, with relation to the above problems, are:

  1. The user does not need to understand the nature of composed applications because they only ever make decisions about the top-level origin.
  2. It is clear how to persist user decisions: they are only ever stored for the top-level origin.
  3. Because decisions are only ever made about the top-level origin, it is much easier to build permission management UI.
  4. Because embedees cannot gain access on their own, embedders are able to police their embedees.

Note that there is a necessary trade-off between scoping permission grants in as fine-grained a manner as possible versus scoping permission grants at a level of granularity that people can understand. See Security Considerations.

Permission delegation is already possible on the web platform. For example, if a person has granted geolocation to an origin in a frame, the origin can expose geolocation data to other, cross-origin frames via postMessage (among other mechanisms). This document describes a new web platform API that enables embedders to delegate permissions in a way that the UA can effectively mediate on behalf of users. In addition to delegating access, the API also exposes means to revoke and query delegated access. We intend for the API to be convenient to invoke and to afford efficient implementations.

3. Delegating Permissions

An embedder is said to show an intent to delegate#intent-to-delegateReferenced in:3. Delegating Permissions (2) (3) (4) (5) (6) (7) (8)3.1. Delegation Via The Declarative API3.2. Delegation Via The Imperative API (2) (3) (4) a permission to an embedee if it indicates that a permission should be delegated to that embedee. There are 2 ways for an embedder to show intent to delegate to an embedee: A declarative syntax in the HTML tag that instantiates the embedee; and an imperative syntax that extends the Permissions interface. These are described below. An embeder can show intent to delegate regardless of whether or not it actually holds the permission itself. Showing an intent to delegate does not mean that the embedee will automatically gain acess to the permission.

In order for a cross-origin embedee to actually gain access to a permission, the UA MUST require that:

  1. The embedder holds that permission itself.
  2. The embedeer is showing an intent to delegate that permission to the given embedee.
  3. The embedee meets the minimum security requirements needed to ask for that permission in the first place. For a powerful feature, such as getUserMedia, this requires that the embedee be running in a secure context. Not all features require that the calling origin be in a secure context or meet other safety standards.

In cases where an embedder is not showing an intent to delegate to an embedee, the UA MUST prevent the embedee from triggering permission prompts to the user, and the UA SHOULD prevent the embedee from acquiring any permissions based on a prior decision made by the user.

As an exception, embedees MUST be able to access permissions that are granted to their associated service worker. These permissions can be trivially accessed by communicating with the service worker so there is no need to require delegation.

UAs MAY also allow cross-origin embedees to acquire permission grants through the use of advanced user configurations, such as custom whitelists (see Reduced User Control for further discussion).

In cases where an embedder has shown intent to delegate to an embedee but the embedder does not yet hold permission, a request to use the permission by the embedee SHOULD trigger an automatic request to use the permission on behalf of the embedder. This allows embedees to acquire access to permissions without embedders having to acquire access up front.

The lifetime of the embedees access to the permission must be tied to the lifetime of the embedders access to the permission. Thus, if the embedder loses access to the permission, the UA MUST revoke access from the embedee.

An embedder can also retract its intent to delegate to an embedee. In this case the UA MUST revoke access to the given permission from the embedee.

If an embedee performs a cross-origin navigation the UA MUST implicitly retract the intent to delegate to that embedee which will cause the embedee to lose access. This prevents unintentionally delegating access to other origins.

UAs SHOULD apply these restrictions to all existing and future permissions defined in the PermissionName enum.

3.1. Delegation Via The Declarative API

The permissions attribute is defined on the iframe element.

partial interface HTMLIFrameElement {
  [PutForwards=value] readonly attribute DOMTokenList permissions;
};

The permissions attribute, when specified, shows an intent to delegate the given set of permissions to the embedee running in the iframe. Its value must be an unordered set of unique space-separated tokens that are ASCII case- insensitive. The allowed values are the permission names that come from the PermissionName enum.

3.2. Delegation Via The Imperative API

The Permissions interface is extended to provide functions for showing and retracting an intent to delegate as well as querying the delegation status.

[Exposed=(Window,Worker)]
partial interface Permissions {
  Promise<void> delegate((PermissionDescriptor or sequence<PermissionDescriptor>) permission);
  Promise<void> undelegate((PermissionDescriptor or sequence<PermissionDescriptor>) permission);
  Promise<boolean> isDelegated(PermissionDescriptor permission);
};

When called with these functions PermissionDescriptor must contain a field which specifies the embedee:

dictionary PermissionDescriptor {
  required PermissionName name;
  HTMLIFrameElement embedee;
};

The embedee specified must be nested in the caller’s browsing context otherwise the request for delegation will be rejected.

The promise returned will resolve if an intent to delegate has been successfully shown, otherwise it will be rejected. Similarly, undelegate will cause the intent to delegate to be retracted.

The isDelegated function returns a promise which will resolve to true if the embedder is expressing an intent to delegate the given permission.

4. Examples

Consider an embedder https://restaurant.example.net whose developers want to show a map on the page that enables people to get directions to the restaurant. They can do so by instantiating an iframe to the maps service https://maps.example.com, and by explicitly delegating the "geolocation" permission:

<iframe id="embedee" src="https://maps.example.com/" permissions="geolocation"></iframe>

Consider next that the developers of https://restaurant.example.net learn of a new feature that https://maps.example.com provides, which is to send people notifications [notifications] when it’s time to leave to get to their destination on time. For example, people may want to know not just the directions to the restaurant, but also to be notified when they should leave to make it by the time their reservation starts. The developers would explicitly grant the embedded iframe a second permission, "notifications":

<iframe id="embedee" src="https://maps.example.com/" permissions="geolocation notifications"></iframe>

Delegation via the imperative API:

var iframe = document.getElementById('embedee');
navigator.permissions.delegate({embedee: iframe, name: 'geolocation'}).then(
  function() {
    // Delegated geolocation.
  }).catch(function() {
    // Delegation failed.
  });

Undelegating permissions:

var iframe = document.getElementById('embedee');
navigator.permissions.undelegate({embedee: iframe, name: 'geolocation'});

Checking whether permission is delegated:

var iframe = document.getElementById('embedee');
navigator.permissions.isDelegated({embedee: iframe, name: 'geolocation'})
  .then(function(result) {
    // result === true
  });

5. Security Considerations

The most obvious downside of this proposal is that it breaks the principle of least privilege. In particular, an embedee can’t get access to a permission without the top-level embedder also getting access to the permission. Thus, the permission grant is broader than is strictly necessary.

For example, consider an airline ticketing site (https://example.air) that embeds a payment processor site (https://example.cc) in an iframe. To better authenticate or verify the purchase of tickets, example.cc requests access to the UA’s geolocation API. Under this proposal, the user would have to grant geolocation API access to the example.air origin, which would then delegate the power to example.cc. The grant would adhere, perhaps persistently, to example.air — regardless of what other origins it may embed — rather than to example.cc.

We could extend this scenario to a potentially more problematic case in which a less trustworthy site (https://example.suspicious) also allows purchases and embeds an example.cc frame for credit card verification. Now the user has to give access to their location to example.suspicious as well as to example.cc to complete their purchase. Obviously, this is not ideal.

Conversely, if embedees can directly request access to powerful features (currently the case in many UAs), people may not understand where the request comes from — although example.air is a composed application, people are often unaware that web applications can be composed of an embedder and potentially several embedees. Thus, when an embedee requests a permission grant, the person may not have any context for or understanding of what the UA is asking them. We believe that people perceive the top-level site as the ‘active application’ — if they perceive any ‘active application’ at all. Thus, we believe that if there is any chance for an origin to be or provide context for a permission request, it is the top-level, embedder origin.

Additionally, embedees can take advantage of this confusion, and request permissions (or otherwise cost the person’s attention) in ways that disrupt the trust relationship between the person and the top-level embedder origin.

This proposal puts the onus on the embedder, which has chosen to embed its embedees, to state the value proposition for the permission grant and to establish a relationship with the person using the application. It also enables and incentivizes embedders to ‘police’ their embedees in order to remain trustworthy.

6. Other Risks

6.1. Compatibility

This document specifies breaking changes to the web platform. Namely, embedees that were once able to request and acquire permissions will no longer be able to do so. In order to restore functionality, embedders need to change their iframe tags to specify which permissions they wish to delegate. Usage of permissions from embedees is currently very low (see [iframe-permissions-chrome]), so the impact of this change should be small. It is recommended that UAs communicate this change with developers prior to implemenation in order to minimize the impact of the change. This can be done through the use of console warning messages or other channels.

The upside of this breakage is that any harmful or annoying permission requests from embedees, which website owners did not intend their users to be exposed to will be prevented.

It should also be noted that the restrictions specified in this document would prevent secure (HTTPS) embedees in non-secure (HTTP) embedders from getting access to permissions. The reason is that the availability of “powerful features” on non-secure origins is being phased out (see [powerful-features]). This means that a top-level embedder would never be able to access a permission in order to delegate it. This is actually not more restrictive than what is specified in [powerful-features], which requires all ancestor frames be secure in order for a frame to be considered secure. The restrictions specified in this document would not result in additional breakages.

6.2. Changing Embedee Permissions

iframe tags tend to be fairly widely copy/pasted. For example, to make it easy for developers to embed YouTube videos, YouTube provides a HTML iframe snippet which can be pasted into a website. Once these snippets have been deployed, it is hard for embedees to have them changed. For example, if the permissions required to run YouTube ever changed, it would be impossible for YouTube to update all of its embedders. While this may be problematic for embedees, it gives embedders an opportunity to decide whether they really want the embedee to have access to the permission.

6.3. Reduced User Control

Some people may want to be able to let an embedee origin they consider trustworthy have access to some permissions, but may not want to grant those same permissions to an embedder they consider untrustworthy. Permission grants adhere to the embedder, which presents a paradox of control: it seems we can present people an option to control permissions at a coarse but understandable granularity; or we can present an option to control permissions at a fine but confusing granularity. (See Background And Motivations.)

UAs may provide advanced configuration options to mitigate this risk. These options would place more control back into the hands of users. For example, a user-controlled whitelist could be used to allow embedees from certain origins to get permission access without delegation. Alternatively, UAs may have an option which allows embedees to independently prompt a user for permission but the decision is not persisted by default. This proposal does not recommend or require any specific mitigation techniques.

Composing origins to create more complex web applications is analogous to application composition from components of different sources on other platforms, and other platforms also tie the principal to just the top-level application. (For a definition of the term principal, see [protection-of-information]).

  • Many Android applications include libraries (often packaged as JARs) from third parties, but the Android platform treats the embedding package as the principal, and adheres permission grants to that package. Consider an email reader, com.example.mail, that includes an IMAP client implemented in a JAR provided by the Foo Organization, that provides the package org.foo.imap.client. Android exposes only com.example.mail to the user, gives it a unique Linux UID, and all permission grants and revocations adhere to com.example.mail. If another package, e.g. org.messaging.android, also happens to use the org.foo.imap.client JAR, the JAR does not have the same permissions in both embedding packages.
  • Many Windows applications include libraries (often packaged as DLLs) from third parties. Similar to the Android example, Windows separates privileges by associating each process with an access token. Processes holding different tokens are protected from each other, regardless of what DLLs they have loaded (even if they have loaded some of the same DLLs) and regardless of the source of those DLLs.

Neither the Android nor Windows platforms afford the user any fine-grained control over the permissions available to code that ‘top-level’ applications depend on. This proposal for the Open Web Platform is consistent with the existing, analogous behavior on other platforms. Reasonable people may disagree on whether or not that is a good thing, but advocates for fine-grained control of dependencies must contend with the problems of user confusion, lack of context, and warning fatigue that fine-grained control would raise, and has proven to raise. TODO(palmer): Get a cite from felt or ainslie on reduced responsiveness to warnings.

7. Acknowledgements

Thanks to Adrienne Porter Felt, Mounir Lamouri, Alex Russell, Ben Wells, and Mike West for advice and feedback.

Conformance

Document conventions

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Conformant Algorithms

Requirements phrased in the imperative as part of algorithms (such as "strip any leading space characters" or "return false and abort these steps") are to be interpreted with the meaning of the key word ("must", "should", "may", etc) used in introducing the algorithm.

Conformance requirements phrased as algorithms or specific steps can be implemented in any manner, so long as the end result is equivalent. In particular, the algorithms defined in this specification are intended to be easy to understand and are not intended to be performant. Implementers are encouraged to optimize.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[HTML]
Ian Hickson. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[PERMISSIONS]
Mounir Lamouri; Marcos Caceres. The Permissions API. 7 April 2015. WD. URL: https://w3c.github.io/permissions/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[SECURE-CONTEXTS-1]
Secure Contexts URL: https://w3c.github.io/webappsec-secure-contexts/
[SERVICE-WORKERS]
Alex Russell; Jungkee Song; Jake Archibald. Service Workers. 25 June 2015. WD. URL: https://slightlyoff.github.io/ServiceWorker/spec/service_worker/
[WHATWG-DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/

Informative References

[geolocation-API]
Andrei Popescu. Geolocation API Specification. 28 May 2015. PER. URL: http://www.w3.org/TR/geolocation-API/
[IFRAME-PERMISSIONS-CHROME]
Raymes Khoury; Chris Palmer. Simplifying &lt;iframe&gt; Permission Scoping in Chrome. URL: https://docs.google.com/document/d/1iaocsSuVrU11FFzZwy7EnJNOwxhAHMroWSOEERw5hO0
[IFRAME-PERMISSIONS-STUDY]
Rebecca Rolfe; Ben Wells; Raymes Khoury. Understanding Permission Requests From Iframes: Cafe Study Results. URL: https://docs.google.com/presentation/d/1suzMhtvMtA11jxPUdH1jL1oPh-82rTymCnslgR3ehEE
[NOTIFICATIONS]
Anne van Kesteren. Notifications API Standard. Living Standard. URL: https://notifications.spec.whatwg.org/
[POWERFUL-FEATURES]
Mike West; Yan Zhu. Privileged Contexts. 24 April 2015. WD. URL: http://www.w3.org/TR/powerful-features/
[PROTECTION-OF-INFORMATION]
Jerome H. Saltzer; Michael D. Schroeder. The Protection of Information in Computer Systems. URL: http://www.cs.virginia.edu/~evans/cs551/saltzer/
[WEBRTC]
Adam Bergkvist; et al. WebRTC 1.0: Real-time Communication Between Browsers. 28 January 2016. WD. URL: http://www.w3.org/TR/webrtc/

IDL Index

partial interface HTMLIFrameElement {
  [PutForwards=value] readonly attribute DOMTokenList permissions;
};

[Exposed=(Window,Worker)]
partial interface Permissions {
  Promise<void> delegate((PermissionDescriptor or sequence<PermissionDescriptor>) permission);
  Promise<void> undelegate((PermissionDescriptor or sequence<PermissionDescriptor>) permission);
  Promise<boolean> isDelegated(PermissionDescriptor permission);
};

dictionary PermissionDescriptor {
  required PermissionName name;
  HTMLIFrameElement embedee;
};