├── .github └── workflows │ └── build.yml ├── .gitignore ├── .pr-preview.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── Permissions.md ├── README.md ├── Scheme.md ├── SecurityPrivacyQuestionnaire.md ├── Updates.md ├── isolated-contexts.bs └── w3c.json /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | pull_request: {} 4 | push: 5 | branches: 6 | - main 7 | jobs: 8 | build: 9 | name: Build 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v3 13 | - uses: w3c/spec-prod@v2 14 | with: 15 | TOOLCHAIN: bikeshed 16 | SOURCE: isolated-contexts.bs 17 | DESTINATION: isolated-contexts.html 18 | GH_PAGES_BRANCH: gh-pages 19 | BUILD_FAIL_ON: warning 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /isolated-contexts.html 2 | -------------------------------------------------------------------------------- /.pr-preview.json: -------------------------------------------------------------------------------- 1 | { 2 | "src_file": "isolated-contexts.bs", 3 | "type": "bikeshed", 4 | "params": { 5 | "force": 1 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | All documentation, code and communication under this repository are covered by the [W3C Code of Ethics and Professional Conduct](https://www.w3.org/Consortium/cepc/). 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Web Platform Incubator Community Group 2 | 3 | This repository is being used for work in the W3C Web Platform Incubator Community Group, governed by the [W3C Community License 4 | Agreement (CLA)](http://www.w3.org/community/about/agreements/cla/). To make substantive contributions, 5 | you must join the CG. 6 | 7 | If you are not the sole contributor to a contribution (pull request), please identify all 8 | contributors in the pull request comment. 9 | 10 | To add a contributor (other than yourself, that's automatic), mark them one per line as follows: 11 | 12 | ``` 13 | +@github_username 14 | ``` 15 | 16 | If you added a contributor by mistake, you can remove them in a comment with: 17 | 18 | ``` 19 | -@github_username 20 | ``` 21 | 22 | If you are making a pull request on behalf of someone else but you had no part in designing the 23 | feature, you can remove yourself with the above syntax. 24 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | All Reports in this Repository are licensed by Contributors 2 | under the 3 | [W3C Software and Document License](http://www.w3.org/Consortium/Legal/2015/copyright-software-and-document). 4 | 5 | Contributions to Specifications are made under the 6 | [W3C CLA](https://www.w3.org/community/about/agreements/cla/). 7 | 8 | Contributions to Test Suites are made under the 9 | [W3C 3-clause BSD License](https://www.w3.org/Consortium/Legal/2008/03-bsd-license.html) 10 | 11 | -------------------------------------------------------------------------------- /Permissions.md: -------------------------------------------------------------------------------- 1 | # High Watermark Permissions Explainer 2 | 3 | ## Introduction 4 | 5 | The dynamic nature of permissions on the web makes reviewing their use more difficult, and makes it impossible to provide guarantees about which capabilities a site might use. Unlike other platforms like Android or iOS, the web doesn’t force developers to declare required permissions up-front. While Permissions Policy can be used to restrict or delegate permissions to child frames, top-level frames can request access to any permission their context is compatible with. 6 | 7 | [Isolated Web Apps](./README.md) rely on packaging and third-party distribution as a central piece of their security model. The inability to audit permissions on the web makes it more difficult for distribution channels (e.g. an enterprise admin or store) to verify that apps aren’t abusing the powerful capabilities provided to them, or provide guarantees that an app’s behavior won’t change without an explicit update. 8 | 9 | This document proposes introducing a new Web App Manifest field that will allow Isolated Web Apps to specify the maximal set of permissions they could request. These permissions will not be automatically granted to the app, but must be specified in the manifest in order for an app’s just-in-time permission requests to be granted. 10 | 11 | Specifying the high watermark for permissions in the manifest will allow distribution channels to more accurately review apps, and communicate to the user with more confidence and clarity what features and capabilities could be used by the app. 12 | 13 | ## Previous Proposals 14 | 15 | ### Manifest Fields 16 | 17 | There have been several proposals to add a permissions allowlist to the manifest (see [w3c/manifest](https://github.com/w3c/manifest) issues [75](https://github.com/w3c/manifest/issues/75), [395](https://github.com/w3c/manifest/issues/395), [798](https://github.com/w3c/manifest/issues/798)), none of which progressed to a specification or prototype. Most of the concerns about these proposals stem from the fact that manifest loading is asynchronous, which raises a couple issues: 18 | 19 | 1. If the purpose of the permissions field is to limit the capabilities of a page, then that can only be meaningfully achieved by applying the restrictions pre-install as well (otherwise uninstalling the app would bypass the restriction). This isn’t feasible because the manifest isn’t available when the page is first loaded, which introduces a race between loading the manifest and running scripts that use the features being restricted. 20 | 2. Manifest updates are also asynchronous and aren’t guaranteed to take effect when other related code changes do. For example, if you were using the manifest to allowlist permissions for your PWA and wanted to introduce a feature that used a new policy-controlled API, the manifest change to allow the permission and the code to use it wouldn’t update at the same time. This potential divergence between the app’s scripts and its manifest makes the state of the app harder to reason about and forces developers to deal with partially updated apps. 21 | 22 | In a packaged context we avoid these issues by tying the manifest to a specific version of the app, and preventing an app from being launched before it is installed. 23 | 24 | Another concern with manifest-based allowlists in PWAs is that developers can create multiple apps on a single origin, but permissions apply to the entire origin. The browser can’t limit an app’s permissions only within its scope without breaking the existing permissions model, and even if the browser attempted to do so, the app could simply navigate to a same-origin URL outside its scope to request a permission it hadn’t declared. This problem doesn’t exist for Isolated Web Apps because their scope is required to be the entire origin (i.e. “/”). 25 | 26 | All of the aforementioned problems are solved in Isolated Web Apps through packaging and manifest restrictions. This proposal relies on these Isolated Web App properties and does not attempt to solve these issues for PWAs in general. 27 | 28 | ### Origin Policy 29 | 30 | From the [Origin Policy Explainer](https://github.com/WICG/origin-policy/tree/7354568d2492d6847f68da21df46274df50c374a#origin-policy): “Origin policy is a web platform mechanism that allows origins to set their origin-wide configuration in a central location, instead of using per-response HTTP headers.” One of the policies that can be configured within an Origin Policy is [Permissions Policy](https://github.com/WICG/origin-policy/blob/7354568d2492d6847f68da21df46274df50c374a/policy-format.md#feature-policy), which would provide a mechanism for pre-declaring which permissions are allowed within an app. We considered using this to implement high watermark permissions, but abandoned it when Origin Policy was [put on hold](https://github.com/WICG/origin-policy/blob/2683f92226052dd363b84620247cdb5f949a4b75/README.md), primarily due the same [asynchronicity issues](https://docs.google.com/document/d/1jptq14gPpuBt3933-Hns2wwrHIW6qpo3xu6Xkfs12N4/edit#) the aforementioned manifest proposals had. 31 | 32 | ## Proposal 33 | 34 | There are two mechanisms to control permissions on the Web today: [Permissions](https://www.w3.org/TR/permissions/) and [Permissions Policy](https://www.w3.org/TR/permissions-policy-1/). Permissions allow the *user* to control whether an origin has access to a permission-controlled feature, while Permissions Policy allows *developers* to control whether an origin can access or request access to a policy-controlled feature. An API is only accessible to a page if both permission mechanisms allow it. 35 | 36 | It is a non-goal to automatically grant access to all permissions listed in the manifest – we want the user to remain in control of the app’s capabilities. Because of this, along with the fact that manifest restrictions represent a developer choice rather than a user choice, Permissions Policy is better suited as a mechanism to enforce these permission restrictions. 37 | 38 | We propose adding a new `permissions_policy` field as an Isolated Web App specific extension to the Web App Manifest spec, which would contain a [policy directive](https://www.w3.org/TR/permissions-policy-1/#policy-directive) that maps [policy-controlled features](https://www.w3.org/TR/permissions-policy-1/#policy-controlled-feature) to an allowlist of origins. This field would define the default Permissions Policy for all top-level frames in an Isolated Web App. The [default allowlist](https://www.w3.org/TR/permissions-policy-1/#default-allowlists) for all policy-controlled features in Isolated Web Apps should default to 'none', and can only be expanded through the new permissions_policy manifest field. Child frame Permission Policies would inherit from their parent frame as they do today. 39 | 40 | ``` 41 | "permissions_policy": { 42 | "geolocation": [ "self", "https://map.example.com" ], 43 | "fullscreen": [ "*" ] 44 | } 45 | ``` 46 | 47 | In this example, geolocation would be made available to any of the app’s top level documents, embedded content on the same origin as the app, and to embedded content loaded from map.example.com. The fullscreen permission would be available for request to the app’s top level documents, and any embedded content. These two permissions would not automatically be granted on app install, and any request for a permission other than geolocation or fullscreen will be automatically denied. 48 | 49 | While the goal of this proposal is to create a high watermark for the permissions that an app can request, the Permissions Policy specified in the manifest may also be used by the browser to inform the installation UI, or customize site settings pages with the relevant permissions in much the same way [First Run Permissions Prompt](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/InstallTimePermissionsPrompt/Explainer.md) proposes (discussed more below). 50 | 51 | ### Interactions with the Permissions-Policy Header 52 | 53 | WebBundles, the packaging format used by Isolated Web Apps, supports specifying response headers, which means developers could send a Permissions-Policy header in their response. These headers could differ from the manifest’s declared policy in both the permissions specified, and the allowlists. If a Permissions-Policy header is received, the header and manifest policies should be combined as follows: 54 | 55 | * For the **set of permissions** declared, the browser should use the intersection of the permissions specified in the manifest and in the headers, and ignore anything that falls outside of that. 56 | * For the **origins in the allowlist** for each permission, the browser should use the intersection of the origins specified in the manifest and in the headers and ignore anything that falls outside of that. It’s worth noting that if an iframe of a certain origin has access to a permission, it is able to grant access to that same permission to any of its own embedded content of any origin it decides. 57 | 58 | ### Default Allowlists 59 | 60 | As stated above, this proposal changes the default allowlist for all policy-controlled features in Isolated Web Apps from ‘\*’ or ‘self’ to ‘none.’ This ensures that any new permissions added after an app is published will not automatically be granted to the app. However, it also means that any new permissions added for existing features would break apps until they’re updated to request the permission. There is precedence for this; the ability to send SharedArrayBuffers via postMessage was placed behind a new [cross-origin-isolation policy](https://github.com/whatwg/html/issues/5435) in 2020. This was safe given how Permissions Policy worked at the time, but could have broken Isolate Web App main frames with these proposed changes. 61 | 62 | It is an open question whether we want to update the Permissions Policy spec to allow 'none' as a default allowlist for Isolated Web Apps, and have the defaults be configurable on a per-feature basis rather than denying all by default. This approach would allow us to enable a subset of existing features by default in Isolated Web Apps (such as `ch-ua-*`, `sync-xhr`, or `cross-origin-isolation`), while letting us make backwards compatibility decisions on a case-by-case basis for future features. 63 | 64 | ## Related Work 65 | 66 | WebExtensions is another packaging format for web-like content that includes permissions in its manifest. It splits permissions into two fields: [permissions](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions) and [optional_permissions](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/optional_permissions). permissions specifies mandatory permissions that will automatically be granted upon extension installation, while optional_permissions specifies permissions that will not automatically be granted, but may be requested by the extension when needed. The permissions_policy field proposed here is similar to the optional_permissions field, except that it operates on policy-controlled features rather than permissions-controlled features. 67 | 68 | Microsoft recently published an explainer for an API called [First Run Permissions Prompt](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/InstallTimePermissionsPrompt/Explainer.md). This proposal also introduces a new permissions-related manifest field, but instead of limiting the app to only the permissions specified in the manifest, it would be used by the browser only to provide a richer install UI and potentially allow the user to pre-grant access to the specified permissions, and would be usable by all PWAs. It is orthogonal to this proposal. 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Isolated Web Apps Explainer 2 | 3 | ## Introduction 4 | 5 | This document proposes a way of building applications using web standard technologies that will have useful security properties unavailable to normal web pages. They are tentatively called Isolated Web Apps (IWAs). Rather than being hosted on live web servers and fetched over HTTPS, these applications are packaged into [Web Bundles](https://wpack-wg.github.io/bundled-responses/draft-ietf-wpack-bundled-responses.html), signed by their developer, and distributed to end-users through one or more of the potential methods described below. 6 | 7 | Additional documents in this repo: 8 | * [Permissions Explainer](./Permissions.md) describes `permissions_policy` manifest field and interaction with the `Permissions-Policy` header. 9 | * [Scheme Explainer](./Scheme.md) describes the `isolated-app:` scheme and signed web bundle IDs. 10 | * [Updates Explainer](./Updates.md) describes the `version`, `update_manifest_url` manifest fields and updating process. 11 | * [Isolated Contexts Specification](https://wicg.github.io/isolated-web-apps/isolated-contexts.html) 12 | 13 | ## Motivating Use Cases 14 | 15 | Content Security Policy (CSP) provides strong protection against cross-site scripting (XSS) vulnerabilities. Transport Layer Security (TLS) and Subresource Integrity (SRI) provide protection against resources being tampered with in transit or when hosted on third-party servers. However, the threat model for some particularly security sensitive applications includes the main application server itself being compromised and serving malicious content. This goes beyond the protections that current policies can provide. An environment stricter than [[SECURE-CONTEXT]](https://w3c.github.io/webappsec-secure-contexts/) is therefore required. 16 | 17 | For example, developers of the private messaging application Signal [concluded](https://github.com/signalapp/Signal-Desktop/issues/871) that it was more secure to distribute their application as a versioned and signed package through an application store. They were concerned that self-hosting a web app would put their users at risk if their servers were compromised to serve malicious code. When Chrome Apps were deprecated, they chose to move their application to the Electron framework and accept the increase the download size and complexity of their application rather than put their users at risk. The developers of WhatsApp, another secure messaging application, have similar concerns and have produced a [browser extension](https://chrome.google.com/webstore/detail/code-verify/llohflklppcaghdpehpbklhlfebooeog) to perform out-of-band validation of the code served to users' browsers. A comparison between that work and this proposal is included at the end of this document. 18 | 19 | A user agent may also force an application to adopt this threat model if the developer needs access to APIs which would make the application an appealing target for XSS or server-side attacks. For example, the [Direct Sockets API](https://wicg.github.io/direct-sockets/) allows a site to make arbitrary network connections. The Fetch Standard defines the [CORS protocol](https://fetch.spec.whatwg.org/#cors-protocol) to carefully control the network requests that sites can make as users browse the web and execute potentially untrustworthy Javascript. Nevertheless, some applications have legitimate needs to make connections that would violate CORS and use protocols other than HTTP. The tradeoff the application developer can make in order to get access to this capability is to accept that user agents need to establish a higher standard for the trustworthiness of the application code and better protection against its compromise by malware. 20 | 21 | ## Non-goals 22 | 23 | This proposal should _not_ be considered a desirable model for most web-based applications. Developers who choose the additional security provided by this proposal give up a number of desirable properties that come from building a web app. An example is the ability for users to discover their application by following a link that drops them into a complete experience rather than having to first install the application. They also lose the ability to quickly deploy updates from their own servers. Most applications do not need the enhanced security that this model offers. Existing methods can protect against many types of attacks without the additional burden of bundling and signing their resources. 24 | 25 | ## Proposed Solution 26 | 27 | The core of this proposal is making application updates explicit. Unlike TLS keys, which have to be available online to establish new connections, the key used to sign the Web Bundle can be kept securely offline and is used infrequently. The channel through which updates are distributed creates another point where the new resources can be checked for potentially malicious content. We propose a new [Integrity Block](https://github.com/WICG/webpackage/blob/main/explainers/integrity-signature.md) format for signing an entire Web Bundle. This is different from bundling [Signed HTTP Exchanges](https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html) because we don’t intend to create a verifiable mirror of a subset of a site’s resources, but a holistically verifiable version of an entire application. For this reason Isolated Web Apps should use a [new scheme](./Scheme.md) for content served from these bundles. 28 | 29 | The reason for this is both practical and philosophical. If the identity of the site were still based on a DNS name, then it would still be vulnerable to a temporary loss of control over that domain or the infrastructure used to validate ownership of the domain. Philosophically, we also want to avoid building an alternative to certificate authorities which shares the same namespace. Isolated Web Apps therefore use a new scheme (tentatively, `isolated-app://`) where the authority section of the URL is based on the public key used to sign the Web Bundle containing the application resources. More details available in the [Scheme Explainer](./Scheme.md). 30 | 31 | An application can be upgraded by replacing its Web Bundle with a new version signed by the same key. Since the key hash is the same, the application retains any local storage associated with the previous version. To prevent downgrade attacks, implementations may require either a [`version`](./Updates.md) [Web Application Manifest](https://www.w3.org/TR/appmanifest/) field, or the signature timestamp to be monotonically increasing. 32 | 33 | The protection against server compromise would be no good if the application could be tricked into loading malicious content from outside its Web Bundle, and so a rigorous Content Security Policy is applied, 34 | 35 | ``` 36 | Content-Security-Policy: base-uri 'none'; 37 | default-src 'self'; 38 | object-src 'none'; 39 | frame-src 'self' https: blob: data:; 40 | connect-src 'self' https: wss: blob: data:; 41 | script-src 'self' 'wasm-unsafe-eval'; 42 | img-src 'self' https: blob: data:; 43 | media-src 'self' https: blob: data:; 44 | font-src 'self' blob: data:; 45 | style-src 'self' 'unsafe-inline'; 46 | require-trusted-types-for 'script'; 47 | ``` 48 | 49 | In this policy `'self'` refers to resources loaded from the application’s Web Bundle since its origin only addresses resources from within the bundle. `'self'` also excludes `blob:`, `filesystem:`, and other local schemes, as well as inline script, which makes it more difficult to use external resources gathered through `fetch()` to change the application's behavior. Cross-origin images, media, iframes, HTTP requests from JavaScript, and WebSocket connections are still allowed so that the application can interact with network resources. 50 | 51 | To further protect these applications from interference from potentially malicious third-party content, they must be [cross-origin isolated](https://web.dev/why-coop-coep/) and so these headers are also applied: 52 | 53 | ``` 54 | Cross-Origin-Opener-Policy: same-origin 55 | Cross-Origin-Embedder-Policy: require-corp 56 | Cross-Origin-Resource-Policy: same-origin 57 | Content-Security-Policy: frame-ancestors 'self' 58 | ``` 59 | 60 | Applying these policies can be accomplished in a couple of ways. Initially we plan to inject these headers into all resources loaded from the bundle. However, since Web Bundles support capturing the HTTP response headers for individual resources, validating that the headers are already present is also an option and would allow applications to customize these protections as long as the modifications can still be considered safe, for example, to add additional `unsafe-hashes` CSP directives so that web frameworks that rely on inline script can still be used. 61 | 62 | The policies above already restrict these applications to loading as the top-level document. However, malicious third-party content can create a confusing and potentially exploitable user experience by navigating to one of the application’s documents in an unexpected way (e.g. navigating directly to an internal settings page). Such sequence breaking attacks are prevented by disallowing cross-origin navigations to the application. The application may only be launched by navigating to its [start\_url](https://developer.mozilla.org/en-US/docs/Web/Manifest/start_url) or similar well-defined entry point such as a [protocol handler](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/URLProtocolHandler/explainer.md) or [Share Target](https://github.com/w3c/web-share-target/). [Launch handling](https://github.com/WICG/sw-launch/blob/main/launch_handler.md) may also provide a safe method to allow more dynamic control over incoming navigations. 63 | 64 | Implementations may choose to make an isolate app behave more “app-like” by only allowing them to be launched in a standalone window and assigning them a separate [storage shed](https://storage.spec.whatwg.org/#storage-shed) so that third-party storage from the user’s normal browsing session is not available. Proposed changes to the web platform in general to reduce access to third-party storage could eventually make the latter the default behavior for any origin. 65 | 66 | Once bundled, an application could be distributed to users in a number of ways: 67 | 68 | * A raw signed Web Bundle. 69 | * Packaged into a platform-specific installation format such as an APK, MSI or DMG. 70 | * Distributed through an operating system, browser or third-party “app store”. 71 | * Automatically installed by enterprise system configuration management infrastructure. 72 | 73 | Implementations may assign different levels of trust depending on the source of the application. For example, an application installed by the system administrator may be implicitly trusted, while one downloaded by the user in the form of an MSI or macOS app bundle may be required to carry the same code signature that a native application for Windows or macOS would. The level of trust required to launch an application should be configurable by the user, with safe defaults. 74 | 75 | ## Related work 76 | 77 | Designing more trustworthy web contexts and packaging applications based on web technologies has been proposed and implemented many times before, 78 | 79 | * Mike West proposed “[Securer Contexts](https://github.com/mikewest/securer-contexts/blob/master/README.md)” upon which the isolation and injection protection presented here are based. 80 | * Google uses signed ZIP archives for both Chrome Apps and Extensions. 81 | * Mozilla's Firefox OS [used](https://wiki.mozilla.org/Apps/Security) a similar packaged app solution with signed ZIP archives and an `app://` protocol scheme. Further planned work on a “[new security model](https://wiki.mozilla.org/FirefoxOS/New_security_model)” was designed to support streaming these packages from HTTPS URLs to improve overall webiness and linkability. 82 | * The [Browser Extension Community Group](https://www.w3.org/community/browserext/) [suggests](https://browserext.github.io/browserext/#packaging) packaging Web Extensions in ZIP archives but leaves the details up to the implementation. 83 | * The [MiniApps Working Group](https://www.w3.org/2021/miniapps/) also [defines](https://w3c.github.io/miniapp-packaging/) a format based on ZIP archives. 84 | * Electron defines a [custom](https://github.com/electron/asar) archive format for efficient loading of application resources. 85 | * Microsoft previously supported building UWP applications using JavaScript which were packaged using MSIX. 86 | * [LG webOS platform](https://www.webosose.org/docs/tutorials/web-apps/developing-external-web-apps/) has supported their own web app packaging format (ipk) with [appinfo.json](https://www.webosose.org/docs/guides/development/configuration-files/appinfo-json/). 87 | * [Delta Chat](https://delta.chat/) and [Cheogram](https://cheogram.com) implement the [webxdc](https://webxdc.org/) archive format for embedding web apps in the context of an encrypted messenger, with all network activity blocked by default. The only way to send and receive data from the web app is by delegating message relay to the (e2e encrypting) messenger. 88 | * [Peergos](https://peergos.org) allows users to install 3rd party web apps from a signed snapshot. Those web apps are run in an [isolated unique-origin iframe](https://peergos.org/posts/a-better-web) locked down so no external communication is possible using COOP,COEP,CORP,CSP. Apps then communicate with the outer Peergos context via post messages where permissions are enforced, like sending E2EE messages to friends, or reading/persisting data. 89 | 90 | ### Comparison to Code Verify 91 | 92 | Meta and Cloudflare have [announced](https://blog.cloudflare.com/cloudflare-verifies-code-whatsapp-web-serves-users/) a collaboration to resolve the same threat of tampering with the code for the WhatsApp web app that this proposal addresses. Their approach is similar to [Binary Transparency](https://binary.transparency.dev/), using [a browser extension](https://github.com/facebookincubator/meta-code-verify) to compare the running code against a manifest of expected hashes that is distributed out-of-band with the application. In this case, the manifest is served by Cloudflare while the site is served by Meta. This has the advantage of not requiring a new way to distribute their application. Users who don’t have the extension installed visit the site as usual, while users with the extension have additional protection. One can imagine a future in which the validation logic is embedded into the browser, bringing this protection to more users. As with [OSCP](https://en.wikipedia.org/wiki/Online_Certificate_Status_Protocol) however, an attacker who can compromise the user’s connection to the site may also be able to compromise their connection to the validation endpoint and the current design fails open. 93 | 94 | This proposal addresses that vulnerability by defining a single moment at which the application is vulnerable to a network attacker, that is, the moment when a bundle is downloaded, and afterwards resources are not fetched over the network. The Code Verify system could be improved by blocking access to the site until the manifest has been fetched, so that only verified resources can be loaded rather than warning the user that the resources have been tampered with after the fact. At that point however, the benefit of individually fetching resources over the network is weakened and using a signed Web Bundle, as proposed here, allows fetching and verification to be completed as a single step. 95 | 96 | ## Discuss & Help 97 | 98 | If you'd like to discuss the Isolated Web Apps proposal itself, please use [GitHub Issues](https://github.com/WICG/isolated-web-apps). 99 | 100 | For discussions related to Isolated Web Apps in general, or Chromium-specific implementation and development questions, please use the [iwa-dev@chromium.org](https://groups.google.com/a/chromium.org/g/iwa-dev) mailing list. 101 | 102 | ## Acknowledgements 103 | 104 | * Alex Russell <alexrussell@microsoft.com> 105 | * Andrew Whalley <awhalley@google.com> 106 | * Mike West <mkwst@google.com> 107 | * Penny McLachlan <pjmclachlan@google.com> 108 | -------------------------------------------------------------------------------- /Scheme.md: -------------------------------------------------------------------------------- 1 | # `isolated-app:` Scheme Explainer 2 | 3 | This document provides a more detailed look at the `isolated-app:` scheme, which is part of the proposal for [Isolated Web Apps](./README.md). 4 | Isolated Web Apps are a new proposal to build applications using web technologies, but with additional security properties compared to normal web pages. 5 | Isolated Web Apps bundle all their contents inside a web bundle that is then [signed to make its integrity verifiable](https://github.com/WICG/webpackage/blob/main/explainers/integrity-signature.md). 6 | A key difference between Isolated Web Apps and normal web pages is that Isolated Web Apps do not rely on DNS name resolution and HTTPS certificate authorities. 7 | Instead, they need to be explicitly downloaded and installed by the user, such as from an app store or via enterprise configuration. 8 | A user agent can verify the integrity of an Isolated Web App by checking the signature and comparing its corresponding public key to a list of known trusted public keys. 9 | 10 | ## `isolated-app:` Scheme 11 | 12 | Since Isolated Web Apps do not use HTTPS certificate authorities and also need to be independent of domains and name resolution, a new URL scheme is needed to signify this difference. 13 | The tentative name of this new scheme is `isolated-app:`, highlighting how Isolated Web Apps are isolated from each other and the web through enforced Content Security Policy and Cross-Origin Isolation. 14 | When loading an `isolated-app:` URL, the user agent checks the signatures of the underlying web bundle and whether it trusts the public key that was used to sign it. 15 | A user agent might trust, for example, public keys configured via enterprise policy, public keys of known distribution mechanisms/stores, or separately allow-listed public keys of individual Isolated Web Apps. 16 | `isolated-app:` URLs are considered Secure Contexts, just like HTTPS pages, and thus have access to APIs like Service Workers. `isolated-app:` URLs look like so: 17 | 18 | ``` 19 | isolated-app://signed-web-bundle-id/path/inside/app.js?some-query#foo 20 | ^ ://^ /^ ?^ #^ 21 | scheme opaque host path query fragment 22 | ``` 23 | 24 | ### Host 25 | 26 | URLs with the `isolated-app:` scheme use a Signed Web Bundle ID (see next section) as their opaque host, as defined in the [URL standard](https://url.spec.whatwg.org/). 27 | The Signed Web Bundle ID being the host adds the requirement that it must be a valid hostname (see [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986)). This requirement is satisfied by using [base32 encoding](https://datatracker.ietf.org/doc/html/rfc4648), with padding removed. 28 | It is the user agent’s responsibility to map the Signed Web Bundle ID contained in the opaque host to an installed Isolated Web App and its associated Web Bundle. The URL path is then used to fetch resources as relative URLs from the bundle. 29 | 30 | ### Port & Credentials 31 | 32 | Isolated Web App URLs do not use usernames, passwords, or ports. 33 | All three of these components are therefore always `null`. 34 | Isolated Web App URLs with a port or credentials must not be loaded and must result in an HTTP error. 35 | 36 | ### Path, Query, Fragment 37 | 38 | These work like one would expect from HTTP(S) URLs, as described in the URL specification. 39 | 40 | ## Signed Web Bundle IDs 41 | 42 | Isolated Web Apps are identified by their _Signed Web Bundle ID_. 43 | The Signed Web Bundle ID is an ASCII string which contains an identifier followed by a suffix that represents the type of identifier. 44 | The general format of Signed Web Bundle IDs looks like this: 45 | 46 | ``` 47 | lowercase(base32EncodeWithoutPadding([identifier] [identifier type] [identifier type length])) 48 | [ ------------ suffix ------------------ ] 49 | ``` 50 | 51 | ### Suffix 52 | 53 | The suffix consists of two parts: The last byte indicates how many bytes are used to describe the identifier type, and the `n` bytes before it are used to describe the identifier type. 54 | Currently, the following two suffixes are defined: 55 | 56 | `0x00 0x00 0x02`: This suffix indicates that the ID is a user-agent-specific value that can be used for testing and development purposes. 57 | For example, loading a Web Bundle from the local filesystem which is not signed. 58 | 59 | `0x00 0x01 0x02`: This suffix is used for [Ed25519](https://datatracker.ietf.org/doc/html/rfc8032) public keys as Signed Web Bundle ID. 60 | It is prefixed by the 32-byte representation of the Ed25519 public key that is used to sign the web bundle (see [this explainer](https://github.com/WICG/webpackage/blob/main/explainers/integrity-signature.md) for more details about the signing process). 61 | Since this Signed Web Bundle ID is only dependent on the signing key, it makes it possible to have the same Signed Web Bundle ID regardless of the distribution mechanism of the Isolated Web App, without requiring a central authority to manage keys. 62 | 63 | ### Encoding 64 | 65 | Given an identifier and the suffix representing the type of the identifier, both must be concatenated and then base32-encoded. 66 | Potential padding introduced by the base32 encoding must be discarded and the result transformed into lowercase. 67 | The resulting string is a Signed Web Bundle ID. 68 | 69 | ### Decoding 70 | 71 | Given a Signed Web Bundle ID, it must first be transformed into uppercase. 72 | If the string's length is not a multiple of 8, a number of padding characters (`=`) must be added until its length is a multiple of 8. 73 | Then, the string must be base32-decoded. 74 | Next, the last byte must be read to determine the length of the identifier type. 75 | Assuming that there are `n` bytes in total and that the last byte contains the number `l`, the `identifier` can be reconstructed by reading bytes `[0, n-l-1)`, and the `identifier type` can be reconstructed by reading bytes `[n-l-1, n-1)`. 76 | 77 | ### Example for Ed25519 keys 78 | 79 | Public Ed25519 key (hex, 32 bytes): 80 | ``` 81 | 01 23 43 43 33 42 7A 14 42 14 82 | a2 b6 c2 d9 f2 02 03 42 18 10 83 | 12 26 62 88 f6 a3 a5 47 14 69 84 | 00 73 85 | ``` 86 | 87 | Public key and suffix (hex, 35 bytes): 88 | ``` 89 | 01 23 43 43 33 42 7A 14 42 14 90 | a2 b6 c2 d9 f2 02 03 42 18 10 91 | 12 26 62 88 f6 a3 a5 47 14 69 92 | 00 73 00 01 02 93 | ``` 94 | 95 | Base32-encoded public key and suffix (56 chars long): 96 | ``` 97 | AERUGQZTIJ5BIQQUUK3MFWPSAIBUEGAQCITGFCHWUOSUOFDJABZQAAIC 98 | ``` 99 | 100 | Since the length of the public key and suffix is a multiple of 5, no padding is generated that would need to be removed. 101 | 102 | Signed Web Bundle ID (56 chars long): 103 | ``` 104 | aerugqztij5biqquuk3mfwpsaibuegaqcitgfchwuosuofdjabzqaaic 105 | ``` -------------------------------------------------------------------------------- /SecurityPrivacyQuestionnaire.md: -------------------------------------------------------------------------------- 1 | ## [2.1 What information might this feature expose to Web sites or other parties, and for what purposes is that exposure necessary?](https://www.w3.org/TR/security-privacy-questionnaire/#purpose) 2 | 3 | The Isolated Web Apps infrastructure on its own exposes less information to site authors because resources are primarily loaded from a local file rather than over the network. While it is not currently in-scope, this proposal provides a big piece of what would be necessary for developers to opt out of network access entirely and build truly "offline-only" applications. [Issue 1](https://github.com/WICG/isolated-web-apps/issues/1) covers the kinds of applications which would benefit from being able to make such a strong privacy guarantee. 4 | 5 | Application updates however still require periodically fetching the [update manifest](Updates.md#web-application-update-manifest) from a developer-controlled server which could allow a developer to track their users by IP address. This can be mitigated by limiting the frequency of update checks or by proxying them through a trusted intermediary to provide IP privacy as discussed in the [Privacy Considerations](Updates.md#privacy-considerations) section of the updates explainer. 6 | 7 | As mentioned in the explainer, user agents may restrict certain APIs or features to IWAs only at the additional integrity guarantees and stronger trustworthiness signals provide a mitigation for their particular security or privacy considerations. This is mentioned here for completeness even though each of those proposals should include their own more thorough justification for why this restriction is an effective mitigation in their own answers to this questionnaire. 8 | 9 | ## [2.2 Do features in your specification expose the minimum amount of information necessary to enable their intended uses?](https://www.w3.org/TR/security-privacy-questionnaire/#minimum-data) 10 | 11 | Yes. The [permissions explainer](Permissions.md) describes that the packaged nature of Isolated Web Apps makes it practical for the developer to declare a [Permissions Policy](https://www.w3.org/TR/permissions-policy/) which applies to the entire application. This allows user agents to inform the user of the permissions the application may request before it is installed. Because updates are explicit, changes to the permission policy can also be inspected when they occur. 12 | 13 | ## [2.3 How do the features in your specification deal with personal information, personally-identifiable information (PII), or information derived from them?](https://www.w3.org/TR/security-privacy-questionnaire/#personal-data) 14 | 15 | Beyond IP addresses, discussed above, this feature does not deal with personal information. 16 | 17 | ## [2.4 How do the features in your specification deal with sensitive information?](https://www.w3.org/TR/security-privacy-questionnaire/#sensitive-data) 18 | 19 | The goal of this proposal is to avoid accidentally exposing sensitive information or capabilities to the web. The required content security, and cross-origin opener, embedder and resource policy headers enforce a higher security baseline than the usual "secure context" definition which should help protect users against XSS attacks and potential leaks of sensitive information. The application-wide Permissions Policy similarly enforces a more secure baseline for what information the application could request. 20 | 21 | Since each Isolated Web App has its own origin on a separate scheme from normal HTTP sites its data is partitioned by the normal storage partitioning mechanism. 22 | 23 | ## [2.5 Do the features in your specification introduce new state for an origin that persists across browsing sessions?](https://www.w3.org/TR/security-privacy-questionnaire/#persistent-origin-specific-state) 24 | 25 | The installed version of the app is a new piece of state. If unique versions of the application's Web Bundle were generated for each user this could be used to track a particular installation over time. This is comparable to concerns over user tracking through the Web Application Manifest start\_url field. Similar to other forms of URL-based tracking this is difficult to mitigate by technical means as it is impossible to automatically detect what part of the URL is the tracking information. 26 | 27 | If a User Agent requires applications to carry a signature indicating that the current version has been reviewed by a third-party then the process for obtaining that signature could be rate limited to prevent abuse. 28 | 29 | ## [2.6 Do the features in your specification expose information about the underlying platform to origins?](https://www.w3.org/TR/security-privacy-questionnaire/#underlying-platform-data) 30 | 31 | Not directly, but as mentioned in the answer to 2.1 above user agents may require developers to build an Isolated Web App to access API features which require a greater level of site security and trustworthiness. The [Direct Sockets API](https://wicg.github.io/direct-sockets/), a proposed IWA-only feature, may expose information about the local network by providing the ability to make network connections not normally allowed over HTTP. 32 | 33 | ## [2.7 Does this specification allow an origin to send data to the underlying platform?](https://www.w3.org/TR/security-privacy-questionnaire/#send-to-platform) 34 | 35 | See the answers to 2.6, 2.10 and 2.16 for mentions of proposed IWA-only APIs which allow access to low-level platform capabilities. 36 | 37 | ## [2.8 Do features in this specification enable access to device sensors?](https://www.w3.org/TR/security-privacy-questionnaire/#sensor-data) 38 | 39 | Not directly, but as mentioned in the answer to 2.1 above user agents may require developers to build an Isolated Web App to access API features which require a greater level of site security and trustworthiness. Currently, there is no proposal for an IWA-only API which enables access to device sensors. 40 | 41 | ## [2.9 Do features in this specification enable new script execution/loading mechanisms?](https://www.w3.org/TR/security-privacy-questionnaire/#string-to-script) 42 | 43 | Yes, this proposal builds on top of Web Bundles to define [a new scheme](Scheme.md) from which resources can be loaded. Since bundled resources are served from a new scheme they are cross-origin to any existing web content. A combination of CSP and additional user agent restrictions also prevent this bundled content from being navigated to or loaded as a subresource by existing web content. 44 | 45 | ## [2.10 Do features in this specification allow an origin to access other devices?](https://www.w3.org/TR/security-privacy-questionnaire/#remote-device) 46 | 47 | Not directly, but as mentioned in the answer to 2.1 above user agents may require developers to build an IWA to access API features which require a greater level of site security and trustworthiness. There is a proposal (explainer to-be-written) to allow an Isolated Web App using the WebUSB API to claim USB device interfaces which are normally [protected](https://wicg.github.io/webusb/#has-a-protected-interface-class). 48 | 49 | ## [2.11 Do features in this specification allow an origin some measure of control over a user agent’s native UI?](https://www.w3.org/TR/security-privacy-questionnaire/#native-ui) 50 | 51 | As with installable web apps, an IWA may run in a minimal UI mode which hides the address bar and other native UI. While presentation details are up to user agents, the explainer recommends user agents use the standalone display mode to emphasize the app-like nature of these sites to establish the right mental model and expectations for users. 52 | 53 | Since the origin (see the more detailed [scheme explainer](Scheme.md)) is not human-readable it is expected that the user agent’s native UI will display the name or short\_name from the Web Application Manifest instead. This is potentially untrustworthy data. Protection against spoofing another application is provided by the installation process confirming the name of the application being installed and user agent policies on trustworthy installation sources. 54 | 55 | Similarly, the short name would appear in settings related to the IWA. For example, settings to view storage consumption and clear storage, or to allow/deny access to web features such as Geolocation. 56 | 57 | As mentioned in the answer to 2.1 above user agents may require developers to build an IWA to access API features which require a greater level of site security and trustworthiness. The [Borderless](https://github.com/sonkkeli/borderless/blob/main/EXPLAINER.md) display mode proposal allows further control over the user agent’s native UI by allowing the window title and borders to be hidden entirely. 58 | 59 | ## [2.12 What temporary identifiers do the features in this specification create or expose to the web?](https://www.w3.org/TR/security-privacy-questionnaire/#temporary-id) 60 | 61 | This feature does not create temporary identifiers. 62 | 63 | ## [2.13 How does this specification distinguish between behavior in first-party and third-party contexts?](https://www.w3.org/TR/security-privacy-questionnaire/#first-third-party) 64 | 65 | This feature only creates a new kind of first-party context. Third-party content may be embedded within an Isolated Web App but it is covered by the web’s normal integrity guarantees rather than the stronger integrity guarantees provided by this proposal for first-party content. First-party content (i.e. content from the developer of the app) which is served dynamically (not part of the Web Bundle) is treated identically to third-party content since any HTTPS origin is cross-origin to an IWA origin. The mandatory Content Security Policy rules are designed to protect an app from exploits launched from compromised third-party content it embeds. 66 | 67 | ## [2.14 How do the features in this specification work in the context of a browser’s Private Browsing or Incognito mode?](https://www.w3.org/TR/security-privacy-questionnaire/#private-browsing) 68 | 69 | An Isolated Web App could be launched inside a "Private Browsing" or "Incognito" mode which would clear state between sessions and prevent embedded third-party content from setting cookies. 70 | 71 | ## [2.15 Does this specification have both "Security Considerations" and "Privacy Considerations" sections?](https://www.w3.org/TR/security-privacy-questionnaire/#considerations) 72 | 73 | The whole set of explainers are basically security considerations. The [updates explainer](Updates.md) specifically calls out security and privacy considerations for the update process. 74 | 75 | ## [2.16 Do features in your specification enable origins to downgrade default security protections?](https://www.w3.org/TR/security-privacy-questionnaire/#relaxed-sop) 76 | 77 | While the intent of distributing an application as a signed Web Bundle is to allow auditing and inspection of the code there are nevertheless ways to inject dynamic behavior such as, fetching content over the network and interpreting it (eval() is blocked, but developers can always implement their own interpreter), loading dynamic content in an iframe, or “laundering” dynamic resources through a Service Worker fetch event handler so that they appear same-origin when evaluating Content Security Policy. The only way to mitigate these workarounds is to inspect the signed Web Bundle and detect these patterns. 78 | 79 | As mentioned in the answer to 2.1 above, user agents may require developers to build an Isolated Web App to access API features which require a greater level of site security and trustworthiness. Three IWA-only APIs have been proposed which downgrade default security protections: 80 | 81 | * The [Direct Sockets API](https://wicg.github.io/direct-sockets/) allows an app to bypass CORS protections when making network requests, does not require connections to use TLS (bypassing mixed-content restrictions), and allows an app to connect to non-HTTP endpoints (bypassing protections against protocol confusion attacks). 82 | * The [Controlled Frame API](https://github.com/chasephillips/controlled-frame/blob/main/EXPLAINER.md) defines an element similar to an <iframe> which allows the app to have a level of control over cross-origin embedded content equivalent to the control the app would have over same-origin embedded content. 83 | * [WebAuthn Remote Desktop Support](https://github.com/w3c/webauthn/wiki/Explainer:-Remote-Desktop-Support) defines an extension to the WebAuthn API which allows trusted remote desktop applications to impersonate another origin in a credential request. 84 | 85 | ## [2.17 How does your feature handle non-"fully active" documents?](https://www.w3.org/TR/security-privacy-questionnaire/#non-fully-active) 86 | 87 | Probably not applicable, this feature doesn’t add any new JavaScript APIs which would have to react to non-"fully active" documents. While it defines a new method for loading resources, navigation between those resources should follow the existing page lifecycle behavior. 88 | 89 | ## [2.18 What should this questionnaire have asked?](https://www.w3.org/TR/security-privacy-questionnaire/#missing-questions) 90 | 91 | It should have asked, "Does this feature depend on user agents or third-parties providing additional security services?" 92 | 93 | As mentioned above some security and privacy issues are mitigated by the fact that a bundled and signed application can be inspected before installation, but who does that inspection? User agents could require that the Web Bundle's Integrity Block contain an additional signature that indicates the version has been submitted for an audit. Browser vendors could run their own audit services or trust third-party services. To avoid centralization, a system similar to Certificate Transparency logs could be used to provide public accountability when developers publish a new version of their application. 94 | -------------------------------------------------------------------------------- /Updates.md: -------------------------------------------------------------------------------- 1 | # Isolated Web App Updates 2 | 3 | ## Purpose 4 | 5 | Isolated Web Apps load resources from a Web Bundle that is stored on the user’s computer rather than from a server. This design necessitates a system for determining when a new version of that Web Bundle should be downloaded. 6 | 7 | ## Proposed Design 8 | 9 | The Web Application Manifest for an Isolated Web App will include two new fields related to updates, 10 | 11 | * the `version` field allows the app publisher to identify a Web Bundle as containing a particular version of the application 12 | * the `update_manifest_url` field tells the user agent where to look for updated versions of the application 13 | 14 | The resource served at the `update_manifest_url` is a JSON document listing versions of the application that are available and the URL from which the Web Bundle containing that version can be downloaded. It also specifies which _Update Channels_ each version is part of. 15 | 16 | In order to check for updates the user agent follows the following steps, 17 | 18 | 1. Fetch the resource from `update_manifest_url` and parse it as a JSON document. 19 | 2. Let _selectedVersion_ and _selectedSrc_ be initialized to `null`. 20 | 3. Let _updateChannel_ be the identifier of the Update Channel the installed app is subscribed to. 21 | 4. For each object in the document’s `versions` entry, 22 | 1. Let _version_ be the object’s `version` field, skipping this item if the field does not exist. 23 | 2. Let _src_ be the object’s `src` field, skipping this item if the field does not exist. 24 | 3. Let _channels_ be the object’s `channels` field, defaulting to a list with a single element named `default` (`["default"]`) if the field does not exist. 25 | 4. If _version_ is not a valid version identifier or _src_ is not a valid URL or _channels_ is not a list of valid channel identifiers, skip this item. 26 | 5. If _channels_ does not include _updateChannel_, skip this item. 27 | 6. If _selectedVersion_ is `null` or _selectedVersion_ is less than or equal to _version_, set _selectedVersion_ to _version_ and _selectedSrc_ to _src_. 28 | 5. If _selectedVersion_ is `null`, abort these steps. 29 | 6. If _selectedVersion_ is less than or equal to the currently installed version, abort these steps. 30 | 7. Fetch the resource from _selectedSrc_. 31 | 8. If the resource is not a valid Signed Web Bundle, abort these steps. 32 | 9. If the Web Bundle ID of the resource is not equal to that of the currently installed app, abort these steps. 33 | 10. Load `/.well-known/manifest.webmanifest` from the Web Bundle and parse it as a Web Application Manifest. 34 | 11. If the resource is not found or fails to parse, abort these steps. 35 | 12. If the `version` field in the manifest from the Web Bundle is not equal to _selectedVersion_, abort these steps. 36 | 13. Replace the Web Bundle for the current installed app with the downloaded resource. 37 | 38 | ## Extensions to the Web Application Manifest 39 | 40 | ### `version` field 41 | 42 | The `version` field contains a string indicating the version of the application. This field is only used and mandatory for Isolated Web Apps, but has no meaning for normal Web Applications. For the purposes of updating version numbers only need to be ordered. For example, a plain integer versioning scheme (e.g. 1, 2, 3, etc.) would be sufficient however for ease of use and to provide for more complex comparisons to be performed on versions a structured format such as “A.B.C.D”, where A, B, C and D are positive integers (or zero) is much more useful. A format such as [Semantic Versioning](https://semver.org/) could also be adopted as it provides even more expressivity. 43 | 44 | Whatever the structure of the version string, a comparison algorithm must be defined so that sorting of and comparisons between versions can be performed in the algorithms defined in this specification. Lexical comparison between version strings is inappropriate. 45 | 46 | ### `update_manifest_url` field 47 | 48 | The optional `update_manifest_url` field indicates the location where the Web Application Update Manifest can be found. It must be an absolute HTTPS URL, or for testing purposes a localhost HTTP URL. 49 | 50 | ## Web Application Update Manifest 51 | 52 | The Web Application Update Manifest is a document listing all application versions available for download. It consists of a single JSON object with a field called `versions` which is a list. Each entry in the list is an object containing at least two fields, `version` and `src`. The `version` field is a string in the same format as the proposed Web Application Manifest `version` field. The `src` field is a URL and is resolved relative to the location of the manifest. It must be an HTTPS URL or a localhost HTTP URL, for testing purposes. The optional `channels` field, if present, is a list of strings representing Update Channel identifiers. If it is not set, it is treated as if it was set to `["default"]`. 53 | 54 | For example, a manifest hosted at `https://developer.example.com/app/updates.json` could contain, 55 | 56 | ```json 57 | { 58 | "versions": [ 59 | { 60 | "version": "5.2.17", 61 | "src": "https://cdn.example.com/app-package-5.2.17.swbn" 62 | }, 63 | { 64 | "version": "5.7.19", 65 | "src": "v5.7.19/package.swbn", 66 | "channels": ["default"] 67 | }, 68 | { 69 | "version": "6.1.13", 70 | "src": "v6.1.13/package.swbn", 71 | "channels": ["default", "beta"] 72 | }, 73 | { 74 | "version": "7.0.6", 75 | "src": "v7.0.6/package.swbn", 76 | "channels": ["beta"] 77 | }, 78 | { 79 | "version": "7.0.99", 80 | "src": "v7.0.99/package.swbn", 81 | "channels": [] 82 | } 83 | ] 84 | } 85 | ``` 86 | 87 | For forward compatibility, implementations MUST ignore keys they do not recognize. When multiple objects in the `versions` have the same `version` field the algorithm above selects the last instance to allow future versions to specify more precise matching rules based on currently undefined properties (e.g. package language). 88 | 89 | ### Update Channels 90 | 91 | Update Channels allow app developers to provide their users with multiple "Release Trains" to choose from. There is a n:m relationship between Update Channels and versions of an app. Each version can belong to multiple channels, and each channel can contain multiple versions. A version belonging to no channels (i.e., a version where `channels` is set to `[]`), is never updated to. 92 | 93 | An Update Channel is identified by its ID, which MUST be a non-empty string. 94 | 95 | An implementation SHOULD give users the option to switch the Update Channel of an installed app. In enterprise contexts, implementations SHOULD give enterprise admins the option to select Update Channels for apps they install for their users. 96 | 97 | It is up to the app developer to define the meaning of Update Channels: 98 | - An app developer could use the `default` channel as their stable channel, but also have a `beta` channel for users who want to test new features, and a `dev` channel for development previews. 99 | - An app developer could use channels to allow users to stay on an older version of the app, but still receive updates. For example, the developer could define a `2.x-LTS` channel, which users who want to keep using version 2.x of the app can switch to. This allows the app developer to simultaneously provide updates to users stuck on older versions of the app, while also providing updates to users on their newest app version. 100 | 101 | #### Translating Update Channel Identifiers 102 | 103 | Each Update Channel has a string-based identifier. An app developer can optionally define human-readable/translated names for their Update Channels. These names are defined in a separate, optional, top-level `channels` field: 104 | 105 | ```jsonc 106 | { 107 | "channels": { 108 | "4-lts": { 109 | "name": "4.x LTS Releases", 110 | // further future properties could go here 111 | }, 112 | "default": { 113 | "name": "Stable Releases", 114 | // further future properties could go here 115 | }, 116 | "alpha": { 117 | // name missing, so it defaults to the ID ("alpha") 118 | } 119 | // entry for beta channel is missing, so its name defaults to its ID ("beta"). 120 | }, 121 | "versions": [ 122 | { 123 | "version": "4.3.99", 124 | "src": "https://example.com/4.3.99.swbn", 125 | "channels": ["4-lts", "default", "beta", "alpha"], 126 | } 127 | // ... 128 | ], 129 | } 130 | ``` 131 | 132 | (The comments are not valid JSON and only part of this example for illustration purposes.) 133 | 134 | Update Channel names can be translated using the HTTP content negotiation mechanism. A user agent SHOULD send requests for Update Manifests with an `Accept-Language` header based on the user's preferred languages. The server SHOULD use it to pick the best available language for Update Channel names, and respond with a localized Update Manifest file. 135 | 136 | ## Alternatives Considered 137 | 138 | ### Direct link to Web Bundle 139 | 140 | A significantly simpler solution which mimics how normal site resources are updated would be to have the Web Application Manifest link directly to a Web Bundle. The problem with this approach is that, 141 | 142 | * Without version numbers it doesn’t provide robust protection against rollbacks, as the value of the Last-Modified header is not part of the Web Bundle. 143 | * Enterprise administrators want the ability to control when new versions are rolled out, which requires multiple versions to be available at once. The update steps above could be augmented to filter available versions based on administrator-defined policy. 144 | 145 | ## Security Considerations 146 | 147 | The Integrity Block prepended to a Web Bundle to form a Signed Web Bundle provides integrity for a single version of an application, however an application which can’t be updated is not useful and so this document proposes a mechanism for doing so. The security of this mechanism relies on the secrecy of the private key used to generate the Integrity Block in order to provide assurance that the real developer of the application has provided the new version of the Web Bundle and on the comparability of the proposed version field in the Web Application Manifest to provide rollback protections. While the Web Application Update Manifest must be delivered over HTTPS to provide some protection against network-based attackers it is insufficient to trust any Web Bundle loaded over HTTPS from the developer’s origin as the threat model for Isolated Web Apps includes the possibility for temporary compromise of the developer’s website. 148 | 149 | ## Privacy Considerations 150 | 151 | The update algorithm requires fetching resources over the network and so care should be taken to do so in a privacy-preserving way. The first step is to ensure all fetches are done in credentialless mode. Even so, requesting the Web Application Update Manifest reveals the public IP addresses of any systems where an application is installed to a developer-controlled server. We can safely assume that when the application itself is launched it may also make network requests and so some privacy can be achieved by trying to match the frequency of update requests to how often the user actually uses the application to prevent an unused application from being used as a tracking vector. This must be balanced with ensuring that application updates are installed in a timely manner so that security vulnerabilities can be patched. A user agent could also request the manifest via a proxy service however this may prevent updates to internally-deployed applications which are not available outside of a private network. 152 | -------------------------------------------------------------------------------- /isolated-contexts.bs: -------------------------------------------------------------------------------- 1 |
  2 | Title: Isolated Contexts
  3 | Shortname: isolated-contexts
  4 | Level: 1
  5 | Group: wicg
  6 | Status: w3c/CG-DRAFT
  7 | ED: https://wicg.github.io/isolated-web-apps/isolated-contexts.html
  8 | Repository: https://github.com/WICG/isolated-web-apps
  9 | 
 10 | Editor: Robbie McElrath 139758, Google LLC https://google.com, rmcelrath@google.com
 11 | 
 12 | Abstract:
 13 |   This specification defines "isolated contexts", which allow user agent
 14 |   implementers and specification authors to enable certain features only when
 15 |   minimum standards of isolation and integrity are met.
 16 | 
 17 | Markup Shorthands: markdown yes
 18 | 
19 | 20 | 37 |
 38 | urlPrefix: https://w3c.github.io/webappsec-csp/; spec:CSP3
 39 |     type: abstract-op
 40 |         text: Get fetch directive fallback list; url: #directive-fallback-list
 41 | urlPrefix: https://w3c.github.io/trusted-types/dist/spec/; spec:trusted-types
 42 |     type: dfn
 43 |         text: require-trusted-types-for-directive
 44 | 
45 |
 46 | {
 47 |   "strict-csp": {
 48 |       "href": "https://web.dev/strict-csp/",
 49 |       "title": "Mitigate cross-site scripting (XSS) with a strict Content Security Policy (CSP)",
 50 |       "authors": [ "Lukas Weichselbaum" ],
 51 |       "date": "15 March 2021"
 52 |   },
 53 |   "securer-contexts": {
 54 |     "authors": [ "Mike West" ],
 55 |     "href": "https://github.com/mikewest/securer-contexts",
 56 |     "title": "Securer Contexts"
 57 |   }
 58 | }
 59 | 
60 | 61 | # Introduction # {#introduction} 62 | 63 | Throughout its existence the web has been evolved into an increasingly capable 64 | application platform. [=Secure Contexts=] formalize transport security, 65 | [=environment settings object/cross-origin isolated capability|Cross Origin 66 | Isolation=] mitigates side-channel attacks, and browsers and operating systems 67 | have experimented with permission interfaces based on selecting particular 68 | files and devices to make access more scoped and understandable to users. Each 69 | of these advancements either improved the safety guarantees of the web 70 | platform, or guided users towards a more accurate expection of a page's 71 | behavior, and unlocked new classes of capabilities that could be brought safely 72 | to the web. 73 | 74 | Despite these advancements, there are some APIs that still cannot safely be 75 | exposed to the web because they violate the web's security primitives in a way 76 | that cannot reasonably be addressed, or cannot be explained clearly enough for 77 | users to make an informed decision about whether or not to grant a site access 78 | to them. If the platform cannot prove that exposing an API to a particular site 79 | is safe, then trust must derive from external attestations. 80 | 81 | Any assertion about the safety or behavior of a page requires knowing the 82 | contents and behavior of the page; attestations are only meaningful if the code 83 | that was vouched for is the same code being executed. Because of this, any 84 | system that delegates trust decisions must be able to verify the integrity of 85 | the code it is running — it must know that it matches the code that was 86 | delegated trust. 87 | 88 | Additionally, capabilities that don't fit within the web's current security 89 | model have the potential to pose a risk to other web content. This risk is 90 | bidirectional: sandbox-piercing capabilities could be used to attack other 91 | sites, and having access to powerful capabilities makes a site a more 92 | attractive target for bad actors. To mitigate these risks, any content that is 93 | granted access to a capability through the mechanisms described in this 94 | specification must be isolated from a user's normal browsing session. 95 | 96 | This specification defines Isolated Contexts, which are environments 97 | that meet a minimum standard of integrity and isolation, and provide a means of 98 | auditing web content for the purpose of trustworthiness attestation, and 99 | isolate this content from the rest of the user's browsing data. 100 | 101 | While this specification focuses on user-agent provided capabilities, Isolated 102 | Contexts could be beneficial for any web page functionality whose threat model 103 | isn't satisfied by the web's security model. For example, the threat model of 104 | some end-to-end encrypted chat applications includes server compromise, which 105 | is not protected against by the web today. The auditability and attestation 106 | enabled by Isolated Contexts could allow these applications to have confidence 107 | in the integrity and providence of the code they are running. 108 | 109 | 110 | # Isolated Contexts # {#isolated-context-info} 111 | 112 | [=Isolated Contexts=] are defined through a series of [[#monkey]] to existing 113 | specifications. 114 | 115 | Integrity is verified through a combination of strict [[CSP]], which ensures 116 | cross-origin executable content cannot be loaded, and an integrity verification 117 | algorithm, which is an abstract mechanism to validate content loaded within a 118 | page. This specification does not mandate a specific validation approach, it 119 | only defines how one would be used to determine if an environment is an 120 | Isolated Context. 121 | 122 | 123 | ## Which APIs should require an Isolated Context? ## {#which-apis} 124 | 125 | As few as possible. Any API that can only be exposed to Isolated Contexts very 126 | likely violates at least one 127 | 128 | design principle of the web, most commonly that 129 | 130 | it should be safe to visit a web page. Before requiring an Isolated Context 131 | to use an API, consider the following questions: 132 | 133 | 1. Is a new Web Platform API the only way to address the problems this API is 134 | trying to solve? Web Extensions and native applications have their place. 135 | 1. If a capability cannot be communicated clearly to users, is there another 136 | way to solve the problem that would be more understandable to users, and 137 | allow them to make informed decisions about what content can access it? 138 | 1. Can the scope of the API be reduced such that it no longer poses an 139 | unacceptable risk if exposed to an average web page? 140 | 141 | If no alternative can be found, requiring an API to run within an Isolated 142 | Context can be considered as a last resort. 143 | 144 | Part of what makes the web such a unique and successful platform is its lack of 145 | gatekeepers. Anyone can purchase a domain name and host their content without 146 | anyone else's approval, and with full access to the Web Platform's API surface; 147 | everyone has equal footing. The security guarantees provided by Isolated 148 | Contexts enable auditability, which in turn enables attestation. The safety 149 | provided by attestation, either by the browser vendor or a third-party, is the 150 | main reason an API would be restricted to Isolated Contexts. Parties providing 151 | attestation services have the potential to become gatekeepers to the Web 152 | Platform, which is not a desirable direction for the platform to move. Browser 153 | vendors must be extremely selective about which APIs they allow in Isolated 154 | Contexts; changing an API so it can be used in a Secure Context should be 155 | strongly preferred whenever possible. 156 | 157 | 158 | ## UI Treatment ## {#ui-treatment} 159 | 160 | This specification focuses on the technical requirements needed to achieve 161 | integrity and isolation, but if Isolated Contexts are being used to enable 162 | powerful capabilities, it is also critical to not violate user expectations. 163 | 164 | Users trust the web because they've been taught that web pages are safe, have 165 | limited access to their device, and that they are in control of this access. All 166 | APIs on the Web Platform have been carefully designed towards this end, with a 167 | goal of ensuring that 168 | 169 | it should be safe to visit a web page. 170 | 171 | Browser vendors should consider whether capabilities restricted to Isolated 172 | Contexts would violate a user's expectation of what a web page is capable of 173 | doing. Violating these expectations would not only damage trust in the site, but 174 | has the risk of damaging a user's trust in the Web Platform as a whole. 175 | 176 | To mitigate this, steps should be taken by the user agent to convey to users 177 | that content running within an Isolated Context is not typical web content. This 178 | could involve an installation flow, or a Web App UI treatment. 179 | 180 | 181 | # Monkey Patches # {#monkey} 182 | 183 | This specification makes the following monkey patches to existing 184 | specifications: 185 | 186 | * Patches to [[CSP]] will define the characteristics of a policy that's robust 187 | enough to meaningfully defend against attack, and enforce that cross-origin 188 | content cannot be loaded. It builds on what we've learned from explorations 189 | like [[strict-csp]] and [[securer-contexts]], pushing developers towards 190 | well-understood and valuable defenses. 191 | 192 | * Patches to [[HTML]] will define the ways in which those CSP characteristics, 193 | along with other security requirements, are evaluated within a given 194 | context, similar conceptually to [=secure context=] and [=environment 195 | settings object/cross-origin isolated capability=]. It will additionally 196 | define [=user agent=] properties needed to verify the integrity of an 197 | [=origin=]'s resources. 198 | 199 | * Patches to [[FETCH]] will add integrity verification to the [=fetch=] 200 | algorithm. 201 | 202 | * Patches to [[WEBIDL]] will define the `[IsolatedContext]` attribute, and 203 | the way it relies on the changes above to control the exposure of a given 204 | WebIDL construct. 205 | 206 | * Patches to [[STORAGE]] will define the double-keying requirements of 207 | [=Isolated Contexts=]. 208 | 209 | 210 | ## Content Security Policy ## {#monkey-csp} 211 | 212 | In [[CSP]], we'll define an algorithm for evaluating the strength of the 213 | amalgamation of policies contained within a [=CSP list=]. We'll define a 214 | few supporting algorithms as well, but [[#csp-injection-mitigation]] 215 | is the core entry point CSP will expose to HTML. 216 | 217 | ### Does a policy meaningfully mitigate injection attacks? ### {#csp-injection-mitigation} 218 | 219 |
220 | A [=CSP list=] |policies| is said to 221 | meaningfully 222 | mitigate injection attacks if the following algorithm returns 223 | "`Meaningful`". Possible return values are "`Meaningful`" and 224 | "`Not meaningful enough`". 225 | 226 |
    227 | 1. Let |meets object requirements|, |meets base requirements|, 228 | |meets script requirements|, |meets style requirements|, 229 | |meets subresource requirements|, and |meets trusted type requirements| 230 | be [=booleans=] whose values are `false`. 231 | 232 | 1. [=For each=] |policy| in |policies|: 233 | 234 | 1. If |policy|'s [=policy/disposition=] is not "`enforce`" or 235 | |policy|'s [=policy/source=] is not "`header`", 236 | [=iteration/continue=]. 237 | 238 | 1. If |policy| [=policy/sufficiently mitigates plugins=], set 239 | |meets object requirements| to `true`. 240 | 241 | 1. If |policy| [=policy/sufficiently mitigates relative URL manipulation=], set 242 | |meets base requirements| to `true`. 243 | 244 | 1. If |policy| [=policy/sufficiently mitigates script execution=], set 245 | |meets script requirements| to `true`. 246 | 247 | 1. If |policy| [=policy/sufficiently mitigates style evaluation=], set 248 | |meets style requirements| to `true`. 249 | 250 | 1. If |policy| [=policy/sufficiently blocks insecure subresources=], set 251 | |meets subresource requirements| to `true`. 252 | 253 | 1. If |policy| [=policy/sufficiently mitigates DOM sinks=], set 254 | |meets trusted type requirements| to `true`. 255 | 256 | 1. Return "`Meaningful`" if |meets object requirements|, 257 | |meets base requirements|, |meets script requirements|, 258 | |meets style requirements|, |meets subresource requirements|, and 259 | |meets trusted type requirements| are all `true`. 260 | 1. Return "`Not meaningful enough`". 261 |
262 |
263 | 264 | ### Obtain the active directive for a type ### {#csp-active-directive} 265 | 266 |
267 | CSP defines a fallback chain for some directives which we need to account for 268 | when evaluating a given policy. To obtain 269 | the active directive given a [=policy=] |policy| and a |directive name|: 270 | 271 |
    272 | 1. Let |fallback chain| be the result of executing Get fetch 273 | directive fallback list on |directive name|. 274 | 275 | 1. [=For each=] |name| in |fallback chain|: 276 | 277 | 1. If |policy|'s [=policy/directive set=] [=set/contains=] a 278 | [=directive=] |directive| whose [=directive/name=] is |name|, 279 | return |directive|. 280 | 281 | 1. Return null. 282 |
283 |
284 | 285 | ### Does a policy sufficiently mitigate plugins? ### {#csp-plugin-mitigation} 286 | 287 |
288 | A [=policy=] |policy| sufficiently mitigates plugins if 289 | the following algorithm returns "`Sufficient`". Possible return values are 290 | "`Sufficient`" and "`Not sufficient`". 291 | 292 |
    293 | 1. Obtain |active directive| from 294 | |policy|, given "`object-src`". 295 | 296 | 1. Return "`Sufficient`" if all of the following are true: 297 | 298 | * |active directive| is not null 299 | * |active directive|'s [=directive/value=]'s [=set/size=] is 1 300 | * |active directive|'s [=directive/value=][0] is an 301 | [=ASCII case-insensitive=] match for the string 302 | "`'none'`". 303 | 304 | 1. Return "`Not sufficient`". 305 |
306 |
307 | 308 | ### Does a policy sufficiently mitigate relative URL manipulation? ### {#csp-relative-url} 309 | 310 |
311 | A [=policy=] |policy| sufficiently mitigates relative URL 312 | manipulation if the following algorithm returns "`Sufficient`". 313 | Possible return values are "`Sufficient`" and "`Not sufficient`". 314 | 315 |
    316 | 1. [=For each=] |directive| in |policy|'s [=policy/directive set=]: 317 | 318 | 1. Return "`Sufficient`" if all of the following are true: 319 | 320 | * |directive|'s [=directive/name=] is "`base-uri`". 321 | * |directive|'s [=directive/value=]'s [=set/size=] is 1 322 | * |directive|'s [=directive/value=][0] is an 323 | [=ASCII case-insensitive=] match for either the string 324 | "`'none'`" or the string "`'self'`". 325 | 326 | 1. Return "`Not sufficient`". 327 |
328 |
329 | 330 | ### Does a policy sufficiently mitigate script execution? ### {#csp-script-mitigation} 331 | 332 |
333 | A [=policy=] |policy| sufficiently mitigates script execution 334 | if the following algorithm returns "`Sufficient`". 335 | Possible return values are "`Sufficient`" and "`Not sufficient`". 336 | 337 |
    338 | 1. Obtain |active directive| from 339 | |policy|, given "`script-src`". 340 | 341 | 1. Return "`Sufficient`" if all of the following are true: 342 | 343 | * |active directive| is not null 344 | * All [=source expressions=] in |active directive| are an 345 | [=ASCII case-insensitive=] match for the strings 346 | "`'none'`", "`'self'`", or 347 | "`'wasm-unsafe-eval'`". 348 | 349 | 1. Return "`Not sufficient`". 350 |
351 |
352 | 353 | ### Does a policy sufficiently mitigate style evaluation? ### {#csp-style-mitigation} 354 | 355 |
356 | A [=policy=] |policy| sufficiently mitigates style evaluation if 357 | the following algorithm returns "`Sufficient`". 358 | Possible return values are "`Sufficient`" and "`Not sufficient`". 359 | 360 |
    361 | 1. [=For each=] |directive| in |policy|'s [=policy/directive set=]: 362 | 1. Obtain |active directive| from 363 | |policy|, given "`style-src`". 364 | 365 | 1. Return "`Sufficient`" if all of the following are true: 366 | 367 | * |directive|'s [=directive/name=] is "`style-src`". 368 | * All [=source expressions=] in |active directive| are an 369 | [=ASCII case-insensitive=] match for the strings 370 | "`'none'`", "`'self'`", or 371 | "`'unsafe-inline'`". 372 | 373 | 1. Return "`Not sufficient`". 374 |
375 |
376 | 377 | ### Does a policy sufficiently block insecure subresources? ### {#csp-subresources} 378 | 379 |
380 | A [=policy=] |policy| sufficiently blocks insecure 381 | subresources if the following algorithm returns "`Sufficient`". 382 | Possible return values are "`Sufficient`" and "`Not sufficient`". 383 | 384 |
    385 | 1. [=For each=] |directive name| in the set [`frame-src`, `connect-src`, 386 | `img-src`, `media-src`, `font-src`]: 387 | 1. Obtain |active directive| 388 | from |policy|, given |directive name|. 389 | 390 | 1. Return "`Not sufficient`" if any [=source expression=] in 391 | |active directive| is **not** an [=ASCII case-insensitive=] match 392 | for the strings "`'none'`", "`'self'`", 393 | "`https:`", "`blob:`", or "`data:`". 394 | 395 | 1. Return "`Sufficient`" 396 |
397 |
398 | 399 | ### Does a policy sufficiently mitigate DOM sinks? ### {#csp-sink-mitigation} 400 | 401 |
402 | A [=policy=] |policy| sufficiently mitigates DOM sinks 403 | if the following algorithm returns "`Sufficient`". 404 | Possible return values are "`Sufficient`" and "`Not sufficient`". 405 | 406 |
    407 | 1. [=For each=] |directive| in |policy|'s [=policy/directive set=]: 408 | 409 | 1. Return "`Sufficient`" if all of the following are true: 410 | 411 | * |directive|'s [=directive/name=] is 412 | "[=require-trusted-types-for-directive|require-trusted-types-for=]". 413 | [[!TRUSTED-TYPES]] 414 | * |directive|'s [=directive/value=] [=set/contains=][0] an 415 | [=ASCII case-insensitive=] match for the string "`'script'`". 416 | 417 | 1. Return "`Not sufficient`". 418 |
419 |
420 | 421 | ### Example ### {#csp-example} 422 | 423 | The following CSP 424 | meaningfully mitigates injection 425 | attacks: 426 | 427 |
428 | base-uri 'none';
429 | default-src 'self';
430 | object-src 'none';
431 | script-src 'self' 'wasm-unsafe-eval';
432 | style-src 'self' 'unsafe-inline';
433 | frame-src 'self' https: blob: data:;
434 | connect-src 'self' https: blob: data:;
435 | img-src 'self' https: blob: data:;
436 | media-src 'self' https: blob: data:;
437 | font-src 'self' blob: data:;
438 | require-trusted-types-for 'script';
439 | 
440 | 441 | ### Does a policy meaningfully mitigate UI Redressing attacks? ### {#csp-ui-redressing-mitigation} 442 | 443 |
444 | A [=CSP list=] |policies| is said to 445 | meaningfully 446 | mitigate UI Redressing attacks [[UISECURITY]] if the following algorithm 447 | returns "`Meaningful`". 448 | Possible return values are "`Meaningful`" and "`Not meaningful enough`". 449 | 450 |
    451 | 1. [=For each=] |policy| in |policies|: 452 | 453 | 1. If |policy|'s [=policy/disposition=] is not "`enforce`" or 454 | |policy|'s [=policy/source=] is not "`header`", 455 | [=iteration/continue=]. 456 | 457 | 1. [=For each=] |directive| in |policy|'s [=policy/directive set=]: 458 | 459 | 1. Return "`Meaningful`" if all of the following are true: 460 | 461 | * |directive|'s [=directive/name=] is "`frame-ancestors`". 462 | * |directive|'s [=directive/value=]'s [=set/size=] is 1 463 | * |directive|'s [=directive/value=][0] is an 464 | [=ASCII case-insensitive=] match for either the string 465 | "`'none'`" or the string "`'self'`". 466 | 467 | 1. Return "`Not meaningful enough`". 468 |
469 |
470 | 471 | 472 | ## HTML ## {#monkey-html} 473 | 474 | In HTML, we'll define a few properties used for resource integrity verification, 475 | and some algorithms used in combination with those defined in 476 | [[#monkey-csp]] to define characteristics of the 477 | [=environment settings object=]. These characteristics will be examined from 478 | [[WEBIDL]] when determining whether or not a given IDL construct is exposed on 479 | the associated [=environment settings object/global object=]. 480 | 481 | ### Integrity ### {#html-integrity} 482 | 483 | An integrity verification algorithm is an 484 | [=implementation-defined=] algorithm that accepts a [=request=] and a 485 | [=response=], and returns a [=boolean=]. 486 | 487 | Note: A typical [=integrity verification algorithm=] might verify that a 488 | response body hashes to an expected value, or that it originated from a known 489 | bundle of resources. 490 | 491 | A [=user agent=] holds an origin integrity verification map, 492 | which is a [=map=] of [=tuple origins=] to 493 | [=integrity verification algorithms=]. 494 | 495 | Note: How user agents populate the [=origin integrity verification map=] is 496 | outside the scope of this specification, which is focused on the properties 497 | needed to establish integrity and isolation. 498 | Isolated Web Apps 499 | provide one possible implementation by basing this map on the set of installed 500 | Isolated Web Apps. 501 | 502 | ### Environment Settings Object properties ### {#html-environment-properties} 503 | 504 |
505 | An [=environment settings object=] is said to 506 | meaningfully mitigate injection 507 | attacks if its [=environment settings object/policy container=]'s 508 | [=policy container/CSP list=] 509 | meaningfully mitigates injection attacks. 510 |
511 | 512 |
513 | An [=environment settings object=] is said to 514 | mitigate UI Redressing attacks 515 | if its [=environment settings object/policy container=]'s 516 | [=policy container/CSP list=] 517 | meaningfully mitigates UI Redressing attacks. 518 |
519 | 520 | Note: Because the definition of meaningful injection and UI Redressing 521 | mitigation for a CSP list depends only upon the header-delivered policies, 522 | these properties will not mutate during an environment's lifetime. 523 | 524 |
525 | An [=environment settings object=] |environment| is an 526 | isolated context if the following algorithm returns `true`: 527 | 1. If |environment| does not [=environment settings object/meaningfully 528 | mitigate injection attacks=], return `false`. 529 | 1. If |environment|'s [=cross-origin isolated capability=] is 530 | not [=concrete=], return `false`. 531 | 1. If |environment| does not [=environment settings object/mitigate UI 532 | Redressing attacks=], return `false`. 533 | 1. Let |origin| be |environment|'s [=origin=]. 534 | 1. If the [=user agent=]'s [=origin integrity verification map=][|origin|] 535 | does not [=map/exist=], return `false`. 536 | 1. Return `true`. 537 |
538 | 539 | 540 | ## Fetch ## {#monkey-fetch} 541 | 542 | In Fetch, we'll use the [=integrity verification algorithm=] defined in 543 | [[#html-integrity]] to verify that responses have the expected contents. 544 | 545 | ### Verify the integrity of a response ### {#fetch-verify-response} 546 |
547 | To verify the integrity of a response given a [=request=] |request| 548 | and a [=response=] |response|, run these steps. Possible return values are 549 | "`not applicable`", "`invalid`", or "`valid`". 550 | 551 |
    552 |
  1. Let |client| be |request|'s [=request/client=].
  2. 553 |
  3. If |client| is `null`, return "`not applicable`".
  4. 554 |
  5. Let |origin| be |request|'s [=request/origin=].
  6. 555 |
  7. 556 | If the [=user agent=]'s [=origin integrity verification map=][|origin|] 557 | does not [=map/exist=], return "`not applicable`". 558 |
  8. 559 |
  9. 560 | Let |integrity verification algorithm| be the [=user agent=]'s 561 | [=origin integrity verification map=][|origin|]. 562 |
  10. 563 |
  11. 564 | If |response|'s [=response/body=] is `null`, return "`invalid`". 565 |
  12. 566 |
  13. 567 | If the result of executing |integrity verification algorithm| given 568 | |request| and |response| is `false`, return "`invalid`". 569 |
  14. 570 |
  15. 571 | Return "`valid`". 572 |
  16. 573 |
574 |
575 | 576 | ### Patches to the "Main Fetch" algorithm ### {#fetch-main-fetch} 577 | The [=main fetch=] algorithm is extended as follows: 578 | 579 |
580 | To main fetch, given a 581 | [=fetch params=] |fetchParams| and an optional boolean 582 | recursive (default false), run these steps: 583 | 584 |
    585 |
  1. Let |request| be |fetchParams|'s [=fetch params/request=].
  2. 586 |
  3. Let |response| be `null`.
  4. 587 |
  5. 588 | If |request|'s [=integrity metadata=] is not the empty string, then: 589 |
    1. ...
    590 |
  6. 591 |
  7. 592 | If the result of executing [=verify the integrity of a response=] given 593 | |request| and |response| is "`invalid`", then run 594 | fetch response 595 | handover given |fetchParams| and a [=network error=]. 596 |
  8. 597 |
  9. 598 | Otherwise, run fetch 599 | response handover given |fetchParams| and |response|. 600 |
  10. 601 |
602 |
603 | 604 | NOTE: Ideally we would integrate integrity verification with [[SRI]]'s 605 | [=integrity metadata=] and its supporting algorithms. That would require a 606 | non-trivial refactoring of how the [[SRI]] specification handles 607 | [=integrity metadata=] strings, which may be worth pursuing in the future. 608 | 609 | 610 | ## WebIDL ## {#monkey-webidl} 611 | 612 | In WebIDL, we'll define the `[IsolatedContext]` attribute, and wire it up to 613 | the hook created in HTML above: 614 | 615 |

616 | [IsolatedContext] 617 |

618 | 619 | If the [{{IsolatedContext}}] [=extended attribute=] appears on an 620 | [=interface=], 621 | [=partial interface=], 622 | [=interface mixin=], 623 | [=partial interface mixin=], 624 | [=callback interface=], 625 | [=namespace=], 626 | [=partial namespace=], 627 | [=interface member=], 628 | [=interface mixin member=], or 629 | [=namespace member=], 630 | it indicates that the construct is [=exposed=] 631 | only within an [=isolated context=]. 632 | The [{{IsolatedContext}}] extended attribute must not be used 633 | on any other construct. 634 | 635 | The [{{IsolatedContext}}] extended attribute must 636 | [=takes no arguments|take no arguments=]. 637 | 638 | If [{{IsolatedContext}}] appears on an [=overloaded=] [=operation=], 639 | then it must appear on all overloads. 640 | 641 | The [{{IsolatedContext}}] [=extended attribute=] must not be specified on more 642 | than one of the following: 643 | 644 | * an [=interface member=] and its [=interface=] or [=partial interface=]; 645 | * an [=interface mixin member=] and its [=interface mixin=] or 646 | [=partial interface mixin=]; 647 | * a [=namespace member=] and its [=namespace=] or [=partial namespace=]. 648 | 649 | Note: This is because adding the [{{IsolatedContext}}] [=extended attribute=] 650 | on a [=member=] when its containing definition is also annotated with the 651 | [{{IsolatedContext}}] [=extended attribute=] does not further restrict the 652 | exposure of the [=member=]. 653 | 654 | An [=interface=] without the [{{IsolatedContext}}] [=extended attribute=] 655 | must not [=interface/inherit=] from another interface 656 | that does specify [{{IsolatedContext}}]. 657 | 658 | ### Patches to the "exposed" algorithm ### {#monkey-webidl-exposed} 659 | 660 | WebIDL's [=exposed=] algorithm is adjusted as follows, adding a single step 661 | after similarly handling [{{CrossOriginIsolated}}] (step 4 below). 662 | 663 |
664 | An [=interface=], [=callback interface=], [=namespace=], or [=member=] 665 | |construct| is exposed in a given 666 | [=realm=] |realm| if the following steps return true: 667 | 668 |
    669 |
  1. 670 | If |construct|'s [=exposure set=] is not *, and 671 | |realm|.\[[GlobalObject]] does not implement an [=interface=] that is in 672 | |construct|'s [=exposure set=], then return false. 673 |
  2. 674 |
  3. 675 | If |realm|'s [=realm/settings object=] is not a [=secure context=], and 676 | |construct| is [=conditionally exposed=] on [{{SecureContext}}], then 677 | return false. 678 |
  4. 679 |
  5. 680 | If |realm|'s [=realm/settings object=]'s 681 | [=environment settings object/cross-origin isolated capability=] is false, 682 | and |construct| is [=conditionally exposed=] on [{{CrossOriginIsolated}}], 683 | then return false. 684 |
  6. 685 |
  7. 686 | If |realm|'s [=realm/settings object=] is not an [=isolated context=], 687 | and |construct| is [=conditionally exposed=] on [{{IsolatedContext}}], 688 | then return `false`. 689 |
  8. 690 |
  9. Return true.
  10. 691 |
692 |
693 | 694 | 695 | ## Storage ## {#monkey-storage} 696 | 697 | The [=obtain a storage key for non-storage purposes=] algorithm is extended to 698 | require double-keying on all storage belonging to an 699 | 700 | environment with a [=top-level origin=] known by the [=user agent=] to have 701 | an [=integrity verification algorithm=]. 702 | 703 |
704 | To obtain a storage key for non-storage purposes, given an 705 | 706 | environment |environment|, run these steps: 707 | 708 |
    709 |
  1. 710 | Let |origin| be |environment|'s [=environment settings object/origin=] if 711 | |environment| is an [=environment settings object=]; otherwise 712 | |environment|'s [=creation URL=]'s [=origin=]. 713 |
  2. 714 | 715 |
  3. 716 | Let |top-level origin| be |environment|'s [=top-level origin=]. 717 |
  4. 718 |
  5. 719 | If the [=user agent=]'s [=origin integrity verification map=] 720 | [|top-level origin|] [=map/exists=], return a [=tuple=] consisting of 721 | |top-level origin| and |origin|. 722 |
  6. 723 | 724 |
  7. 725 | Return a [=tuple=] consisting of |origin|. 726 |
  8. 727 |
728 |
729 | 730 | Note: This is essentially a minimally-specified version of 731 | 732 | Client-Side Storage Partitioning. When that is fully specified and merged 733 | into the necessary specifications, those changes will supersede this section, 734 | and it can be removed. 735 | -------------------------------------------------------------------------------- /w3c.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": [80485] 3 | , "contacts": ["yoavweiss"] 4 | , "repo-type": "cg-report" 5 | } 6 | --------------------------------------------------------------------------------