├── .github └── workflows │ └── build.yml ├── .gitignore ├── .pr-preview.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── Makefile ├── README.md ├── adjacent_work ├── TurtledoveSequenceDiagram.png └── TurtledoveWorklets.md ├── alternate_usecases_analysis └── PrompltessUnpartitionedStorageAccess.md ├── explainer ├── README.md ├── TAG_Security_Privacy_Questionnaire.md ├── fenced_frame_config.md ├── fenced_frame_config_context.md ├── fenced_frames_with_local_unpartitioned_data_access.md ├── generic_payment_button.png ├── integration_with_web_platform.md ├── interaction_with_content_security_policy.md ├── network_side_channel.md ├── opaque_ads_use_cases.md ├── permission_document_policies.md ├── permissions_policy_for_API_backed_fenced_frames.md ├── personalized_payment_button.png ├── process_isolation.md ├── storage_cookies_network_state.md └── use_cases.md ├── meetings └── TPAC2024Notes.md ├── spec.bs └── w3c.json /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | pull_request: {} 4 | push: 5 | branches: 6 | - master 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: spec.bs 17 | DESTINATION: index.html 18 | GH_PAGES_BRANCH: gh-pages 19 | BUILD_FAIL_ON: warning 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | spec.html 2 | out 3 | -------------------------------------------------------------------------------- /.pr-preview.json: -------------------------------------------------------------------------------- 1 | { 2 | "src_file": "spec.bs", 3 | "type": "bikeshed" 4 | } 5 | -------------------------------------------------------------------------------- /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 under the [W3C Software and Document License](http://www.w3.org/Consortium/Legal/2015/copyright-software-and-document). 2 | 3 | Contributions to Specifications are made under the [W3C CLA](https://www.w3.org/community/about/agreements/cla/). 4 | 5 | Contributions to Test Suites are made under the [W3C 3-clause BSD License](https://www.w3.org/Consortium/Legal/2008/03-bsd-license.html). 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL=/bin/bash 2 | 3 | local: spec.bs 4 | bikeshed --die-on=warning spec spec.bs spec.html 5 | 6 | watch: spec.bs 7 | bikeshed watch --die-on=warning spec.bs spec.html 8 | 9 | spec.html: spec.bs 10 | @ (HTTP_STATUS=$$(curl https://api.csswg.org/bikeshed/ \ 11 | --output spec.html \ 12 | --write-out "%{http_code}" \ 13 | --header "Accept: text/plain, text/html" \ 14 | -F die-on=warning \ 15 | -F file=@spec.bs) && \ 16 | [[ "$$HTTP_STATUS" -eq "200" ]]) || ( \ 17 | echo ""; cat spec.html; echo ""; \ 18 | rm -f spec.html; \ 19 | exit 22 \ 20 | ); 21 | 22 | remote: spec.html 23 | 24 | clean: 25 | rm spec.html 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fenced Frames 2 | 3 | This is the repository for Fenced Frames. 4 | 5 | See the [draft specification](https://wicg.github.io/fenced-frame). 6 | 7 | The explainer is organized as follows: 8 | 9 | * What is a fenced frame: the concept, HTML element, security and privacy considerations 10 | * [explainer/README](https://github.com/WICG/fenced-frame/tree/master/explainer) 11 | 12 | * What are the problems being solved/ different modes of fenced frames? 13 | * [Modes/Use cases of fenced frames](https://github.com/WICG/fenced-frame/blob/master/explainer/use_cases.md) 14 | 15 | * How fenced frames integrates with the web platform. This is a growing list of things and will be added to the documentation 16 | * [Integration with the web platform](https://github.com/WICG/fenced-frame/blob/master/explainer/integration_with_web_platform.md) 17 | 18 | 19 | -------------------------------------------------------------------------------- /adjacent_work/TurtledoveSequenceDiagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WICG/fenced-frame/0fd535135e33ec42dc2cdb1b5fd4e0923d3da565/adjacent_work/TurtledoveSequenceDiagram.png -------------------------------------------------------------------------------- /adjacent_work/TurtledoveWorklets.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* 4 | 5 | - [Turtledove Worklets](#turtledove-worklets) 6 | - [Motivation and privacy threat model](#motivation-and-privacy-threat-model) 7 | - [Design](#design) 8 | - [Isolation characteristics](#isolation-characteristics) 9 | - [JS Execution context and thread/process](#js-execution-context-and-threadprocess) 10 | - [Worklet per functionality per origin](#worklet-per-functionality-per-origin) 11 | - [Performance and lifetime considerations](#performance-and-lifetime-considerations) 12 | - [Isolation from extensions](#isolation-from-extensions) 13 | - [Types of Worklets](#types-of-worklets) 14 | - [Privacy and Security considerations](#privacy-and-security-considerations) 15 | 16 | 17 | 18 | # Turtledove Worklets 19 | 20 | (Not to be confused with Worklets Web API as these Javascript contexts are not web-platform visible but are created by the browser.) 21 | 22 | ## Motivation and privacy threat model 23 | 24 | [TURTLEDOVE](https://github.com/WICG/turtledove) requires the browser to run custom javascripts, written by the various actors (like an ad-tech or publisher or advertiser) that participate in the [on-device auction](https://github.com/WICG/turtledove#on-device-auction) of ads. The on-device auction requires signals from the publisher page as well as looking at the interest groups the user is part of and makes the winning ad decision based on both of these. 25 | 26 | Since this environment has both the user’s unpartitioned (available across all sites) information - the interest groups, as well as the publisher page’s information, it can join these two. If this joined information is persisted or sent to a server, it can lead to the advertiser network knowing the user’s browsing history or the user’s identity on the publisher page. It can also lead to the publisher page knowing the interest group that the user belongs to. These are contrary to the [privacy guarantees](https://github.com/WICG/turtledove/blob/main/Original-TURTLEDOVE.md#introduction) that TURTLEDOVE is designed to enforce. 27 | 28 | To mitigate these privacy threats, this JS environment needs to be isolated and cannot access the network, storage or exfiltrate any information to the publisher page. 29 | 30 | 31 | ## Design 32 | 33 | The TURTLEDOVE worklet is an isolated Javascript execution environment that acts as a pure function and does not exfiltrate any data it has access to via its inputs or the results of invoking browser APIs. 34 | 35 | Let’s dive deeper into how this environment will be used by looking at the end-to-end workflow. 36 | 37 | 38 | 39 | * **Creation**: The TURTLEDOVE worklets are created from within the TURTLEDOVE APIs and not by the webpage (unlike other web worklets e.g. animation worklet etc.), therefore this explainer does not introduce any web facing API for its creation. For example, the TURTLEDOVE API is the one that is invoked by the JS running in the publisher page environment, and that in turn creates the worklet to run various pieces of ad-tech-written code in. For more details on the TURTLEDOVE APIs, see [here](https://github.com/WICG/turtledove/blob/master/FLEDGE.md). 40 | * **Allowed APIs**: The worklets will be allowed to execute only a minimal set of APIs (list of which needs to be created). The reporting worklet will access the [aggregate reporting API](https://github.com/csharrison/aggregate-reporting-api). 41 | * **Network access**: Since the worklet has access to the publisher page information as well as user’s cross-site data (e.g. ad interest groups), the worklet can join them, thus enabling user’s browsing history tracking by the ad-tech network. To mitigate the exfiltration of this joined data the worklet is not allowed network access. 42 | * **Storage access**: For similar reasons, the worklet should also not be able to persist information e.g. in local storage etc. The worklet should not have access to storage. 43 | * **Communication with the page**: Since the worklet has access to user’s interest groups, it cannot share that with the embedding page and thus communication to the embedding page is not allowed. 44 | * **Restricted Outputs**: The winning ad output from the worklet needs to be further worked upon by the TURTLEDOVE API for the following aspects: 45 | * Confirm if the output is k-anonymous i.e. the same ad is seen by ‘n’ other browsers. If not, re-run the auction logic. 46 | * Map the winning ad url to an opaque url before passing it back to the publisher page. 47 | 48 | ## Isolation characteristics 49 | 50 | This section goes into the isolation characteristics of the worklets. 51 | 52 | 53 | ### JS Execution context and thread/process 54 | 55 | Each worklet will be a separate JS execution context (e.g. in Chromium, a separate [V8 context](https://chromium.googlesource.com/chromium/src/+/master/third_party/blink/renderer/bindings/core/v8/V8BindingDesign.md#Context)). A TURTLEDOVE worklet needs to execute off the main thread to make sure the bidding and auction logic do not slow down the main thread. The design will go into more details about the process isolation of the worklets, but a high level overview is that these worklets will benefit by being placed in separate processes than the publisher page so that other compromised renderer processes are not able to alter the sensitive data e.g. bidding price, interest group data, present in these worklets. This is aligned with the threat model for Chromium’s [site isolation](https://www.chromium.org/Home/chromium-security/site-isolation). The design will also discuss protection of the worklets from spectre attacks. 56 | 57 | 58 | ### Worklet per functionality per origin 59 | 60 | TURTLEDOVE requires multiple types of worklets for different functionality as mentioned in the section [“Types of Worklets”](#types-of-worklets). An ideal separation between these different worklets is to run each script provided by the different entities like DSP, SSP etc. for different functionalities like bidding, auction etc., in a separate worklet. This will make it easier to restrict the input information flowing into each of these worklets and to enforce privacy guarantees. Examples of how this isolation will help are: 61 | 62 | 63 | 64 | * Bidding logic from one buyer/origin should not impact the bidding logic from another buyer. 65 | * Bidding logic cannot impact the auction logic by setting global variables in the JS context. 66 | 67 | #### Performance and lifetime considerations 68 | 69 | The TURTLEDOVE worklets from one origin being isolated from those of other origins is a hard privacy and security requirement. Similarly, these worklets are scoped to a document and cannot be reused if the top-level page navigates since worklets have the publisher page info and that cannot be leaked across navigations. 70 | 71 | From a performance standpoint, considering that creating multiple worklets/JS contexts for a document is going to be some amount of performance/memory cost and to keep that cost down, browsers might want to create one worklet per origin for one mode (buyer/seller) and use it across various ads on the page instead of creating them separately for each interest group for each ad. The decision to re-use a worklet across ads will not be deterministic and depends on the browser. On the other hand, if there is just a single context for all ad-slots for one DSP, it may mean that the auctions of the various ad slots are sequentially executed leading to ad loading delays. There needs to be a more detailed design of how this can be optimized. 72 | 73 | 74 | ### Isolation from extensions 75 | 76 | Although bidding/auction scripts that are executed inside the worklets are free to be blocked by extensions installed by the user, there is a risk to the integrity of the ads auction if the scripts are allowed to be modified by a potentially malicious extension or if a malicious extension is able to execute in the script’s context. This is because TURTLEDOVE moves sensitive server side bidding and auction logic to the browser. 77 | 78 | Note that the isolation from extensions mentioned in this section is scoped to modification by extensions and not blocking of content by extensions which will be allowed to proceed as for regular network requests. 79 | 80 | The following safeguards help to achieve that goal within the worklet: 81 | 82 | 83 | 84 | * As discussed more in the design section below, a separate V8 context guarantees that an extension cannot directly execute in that context. 85 | * Since the worklet does not have access to the DOM, it guarantees that the extension cannot mutate the DOM to affect the worklet. 86 | * Since the worklet does not access the network, it will not be affected by APIs like WebRequest. 87 | 88 | TURTLEDOVE/FLEDGE do have other network accessing parts like fetching the scripts to run in the worklets and [trusted server interaction](https://github.com/WICG/turtledove/blob/master/FLEDGE.md#31-fetching-real-time-data-from-a-trusted-server) for real-time signals and blocking of those network requests by extensions will be allowed. However, it needs more detailed design to understand if/whether those will need to be restricted modification by extensions or would they instead be verified server-side to confirm that an unmodified script was executed. 89 | 90 | ## Types of Worklets 91 | 92 | As discussed in [FLEDGE](https://github.com/WICG/turtledove/blob/master/FLEDGE.md), TURTLEDOVE will require worklets for its various functionalities, including: 93 | 94 | 95 | 96 | * **Bidding**: The worklet responsible for executing the bidding script. For more details about the responsibilities of this worklet, see [here](https://github.com/WICG/turtledove/blob/master/FLEDGE.md#32-on-device-bidding). 97 | * **Auction**: The worklet responsible for executing the auction script. For more details about the responsibilities of this worklet, see [here](https://github.com/WICG/turtledove/blob/master/FLEDGE.md#23-scoring-bids). 98 | * **Reporting**: The reporting worklet will be responsible for getting inputs from various parts of the page as given below and creating an event-level report (for FLEDGE as MVP) or an [aggregated report](https://github.com/csharrison/aggregate-reporting-api) (long-term) based on those inputs. These reports can be used for various uses like impression counting, conversion measurement, determining fraud or abuse, diagnostics/error reporting etc. Detailed design for these reports needs to be done. 99 | * Publisher page provides inputs like viewability events for the fenced frame, ancestor origins etc. 100 | * Ad rendered in the fenced frame provides inputs like click time etc. 101 | * Bidding/Auction worklet provides inputs like winning ad price and diagnostics like JS errors, determining if codepaths are still live, latency measurement, etc. 102 | 103 | 104 | ## Privacy and Security considerations 105 | 106 | Privacy and Security considerations have been detailed in the sections on [“Design”](#design) and [“Isolation characteristics”](#isolation-characteristics). 107 | 108 | In addition to those, since TURTLEDOVE is sensitive in nature and requires protections against MitM-type attacks like modifying the bidding script/values on the network, these can only be fetched via HTTPS. This is in line with the guidance [here](https://www.chromium.org/Home/chromium-security/prefer-secure-origins-for-powerful-new-features). 109 | -------------------------------------------------------------------------------- /alternate_usecases_analysis/PrompltessUnpartitionedStorageAccess.md: -------------------------------------------------------------------------------- 1 | # Fenced frames and promptless unpartitioned storage access 2 | 3 | 4 | 5 | ## Introduction 6 | 7 | This document goes into the details of promptless unpartitioned storage access as a potential use case of fenced frames ([privacyCG discussion](https://github.com/privacycg/storage-access/issues/41)). For fenced frames concept and design please see the [explainer](https://github.com/WICG/fenced-frame). 8 | 9 | 10 | ## Unpartitioned storage access 11 | 12 | The fenced frame does not have storage access by default. We want the fenced frame to have access to unpartitioned storage, if needed. 13 | 14 | The storage access will be gated behind a user gesture and the states of a fenced frame would be: 15 | 16 | 17 | 18 | 1. Start 19 | * No storage access 20 | 2. On user activation and requesting storage access 21 | * Read/write unpartitioned state access granted 22 | 23 | There are a number of use cases for unpartitioned storage access. These include embedded media playing and enqueueing, document viewing and editing, social widgets, and article comments. requestStorageAccess within the fenced frame can be used to fulfill these use cases. 24 | 25 | Although many of these use cases could be handled with a combination of user identification and server-side storage, the common way to identify users today is from their storage (cookies). Also, any offline use cases (such as offline docs) would require client-side storage. 26 | 27 | 28 | ### Challenges 29 | 30 | requestStorageAccess is used to provide access to unpartitioned storage. When invoked within fenced frames, the goal is to not show a permission prompt, thanks to the communication isolation of a fenced frame. However, that is dependent on mitigating challenges like link decoration, network timing etc. as discussed in the thread [here](https://github.com/privacycg/storage-access/issues/41#issuecomment-673057755). 31 | 32 | 33 | ## Alternative state machine considered 34 | 35 | An alternative that was considered was to provide read-only access to the storage if requested before user activation which can later be converted to read-write storage. Before user activation, unpartitioned storage is only available in a read-only mode to make sure that any bits of information that may have been passed along to the fenced frame e.g. using frame size, is not persisted. But once the read-only data is provided, network access is disabled until user activation. The state machine then becomes. 36 | 37 | 38 | 39 | 1. Start 40 | * Full network access, no storage access 41 | 2. On requesting read-only storage access without user activation 42 | * No network access, read-only unpartitioned state (if requested) 43 | 3. On user activation 44 | * Full network access, read/write unpartitioned state (if requested) 45 | 46 | Downsides 47 | 48 | 49 | 50 | * Increased complexity since allowing read-only access in certain storage mechanisms like IndexedDB, can lead to side channels, for example holding a transaction open for a read could be inferred by observing blocked read-write operations in another context. 51 | -------------------------------------------------------------------------------- /explainer/README.md: -------------------------------------------------------------------------------- 1 | **Table of Contents** 2 | 3 | - [Explainer - Fenced Frames](#explainer---fenced-frames) 4 | - [Authors](#authors) 5 | - [Introduction](#introduction) 6 | - [Goals](#goals) 7 | - [Design](#design) 8 | - [Fenced frame API](#fenced-frame-api) 9 | - [New element type - a top-level browsing context](#new-element-type---a-top-level-browsing-context) 10 | - [Example usage](#example-usage) 11 | - [Benefits over nested browsing context](#benefits-over-nested-browsing-context) 12 | - [Downsides of a new element](#downsides-of-a-new-element) 13 | - [Fenced frame tree](#fenced-frame-tree) 14 | - [Information channel between fenced frame and other frames](#information-channel-between-fenced-frame-and-other-frames) 15 | - [Security considerations](#security-considerations) 16 | - [Privacy considerations](#privacy-considerations) 17 | - [Ongoing technical constraints](#ongoing-technical-constraints) 18 | - [Parallels with Cross-site portals](#parallels-with-cross-site-portals) 19 | - [API alternatives considered](#api-alternatives-considered) 20 | - [Using iframe with document policy](#using-iframe-with-document-policy) 21 | - [Using a new iframe attribute](#using-a-new-iframe-attribute) 22 | - [Using Feature policy/Permission policy](#using-feature-policypermission-policy) 23 | 24 | 25 | 26 | # Explainer - Fenced Frames 27 | 28 | ## Authors 29 | * Shivani Sharma 30 | * Josh Karlin 31 | 32 | ## Introduction 33 | In a web that has its cookies and storage partitioned by top-frame site, there are occasions (such as [Interest group based advertising](https://github.com/WICG/turtledove) or [Conversion Lift Measurements](https://github.com/w3c/web-advertising/blob/master/support_for_advertising_use_cases.md#conversion-lift-measurement)) when it would be useful to display content from different partitions in the same page. This can only be allowed if the documents that contain data from different partitions are isolated from each other such that they're visually composed on the page, but unable to communicate with each other. Iframes do not suit this purpose since they have several communication channels with their embedding frame (e.g., postMessage, URLs, size attribute, name attribute, etc.). We propose fenced frames, a new element to embed documents on a page, that explicitly prevents communication between the embedder and the frame. 34 | 35 | ## Goals 36 | 37 | The fenced frame enforces a boundary between the embedding page and the cross-site embedded document such that user data visible to the two sites is not able to be joined together. This can be helpful in preventing user tracking or other privacy threats. 38 | 39 | **Caveat:** It could still be possible for documents colluding via covert channels to be able to communicate information (See [Ongoing technical constraints](#ongoing-technical-constraints) for more details). 40 | 41 | The privacy threat addressed is: 42 | 43 | **The ability to correlate the user’s identity/information on the embedding site with that on the embedded site.** 44 | 45 | The different use cases and their privacy models are discussed [here](https://github.com/WICG/fenced-frame/blob/master/explainer/use_cases.md). 46 | 47 | ## Design 48 | 49 | Fenced frames are embedded contexts that have the following characteristics to prevent embedder identifiers from being joined with identifiers from the embedded site: 50 | 51 | 52 | 53 | * They’re not allowed to communicate with the embedder and vice-versa, except for certain information such as limited size information. 54 | * They access storage and network via unique partitions so no other frame outside a given fenced frame document can share information via these channels. This is described [here](https://github.com/WICG/fenced-frame/blob/master/explainer/storage_cookies_network_state.md). 55 | * They may have access to browser-managed, limited unpartitioned user data, for example, turtledove interest group. 56 | 57 | The idea is that the fenced frame should not have access to both of the following pieces of information and be able to exfiltrate a join on those: 58 | 59 | 60 | 61 | * User information on the embedding site 62 | * Accessible via communication channels 63 | * Information from other top-site partitions 64 | * Accessible via an API (e.g., Turtledove) or via access to unpartitioned storage 65 | 66 | 67 | A primary use case for fenced frames is to load content that depends on values in another partition’s storage. For example, in Turtledove, we pick an ad based on the user's interest groups (which are joined while browsing other sites) and load it in a fenced frame. The URL of the ad reflects the user's interest group memberships, which is a form of cross-site data, therefore we store the URL for the ad creative _opaquely_ in a fenced frame config (details [here](https://github.com/WICG/fenced-frame/blob/master/explainer/fenced_frame_config.md)). The embedder can use this object to load the ad resulting from the Turtledove auction, but can't inspect it to determine _which_ ad won. 68 | 69 | We expect some leakage of information to be possible via network timing attacks. The side channel and some mitigations are described [here](https://github.com/WICG/fenced-frame/blob/master/explainer/network_side_channel.md). 70 | 71 | ### Fenced frame API 72 | 73 | The proposed fenced frame API is to have a new element type and treat it as a [top-level browsing context](https://html.spec.whatwg.org/#top-level-browsing-context). This section details this approach and later we also describe the alternative API approaches that were considered. 74 | 75 | 76 | #### New element type - a top-level browsing context 77 | 78 | In this approach, a fenced frame behaves as a top-level browsing context that is embedded in another page. This is aligned with the model that a fenced frame is similar to a “tab” since it has minimal communication with the embedding context and is the root of its frame tree and all the frames within the tree can communicate normally with each other. 79 | Since fenced frames are embedded frames, they also behave like iframes in many ways. For example: 80 | * Browser extensions will access a fenced frame as an iframe, e.g., for ad blocking. 81 | * Browser features like accessibility, developer tools etc. will access a fenced frame like an iframe. 82 | 83 | 84 | ##### Example usage 85 | 86 | 87 | ``` 88 | const fencedframe = document.createElement('fencedframe'); 89 | fencedframe.config = new FencedFrameConfig('demo_fenced_frame.html'); 90 | ``` 91 | 92 | * Browser lets the server know via a new [`sec-fetch-dest`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Sec-Fetch-Dest) header value `fencedframe` to let it know that a request is from a fenced frame tree. 93 | * The server needs to opt-in to be loaded in a fenced frame or in an iframe embedded in a fenced frame tree. Without an opt-in, the document cannot be loaded. For opt-in, we use the [supports-loading-mode](https://github.com/jeremyroman/alternate-loading-modes/blob/main/opt-in.md#declaration) header with a new value of `fenced-frame`. 94 | 95 | ##### Benefits over nested browsing context 96 | 97 | 98 | 99 | * Simpler to spec since the fenced frame aligns well with a top-level browsing context. 100 | * Simpler to achieve the communications restrictions with the embedding context, being a top-level browsing context. 101 | 102 | 103 | ##### Downsides of a new element 104 | 105 | 106 | 107 | * Existing sites need to change to embed a new element. This is not really a downside though, since even if it was an enhancement to the iframe element, existing sites would have needed to make changes either in the attributes or in the headers to differentiate it from a regular iframe. 108 | 109 | 110 | ### Fenced frame tree 111 | 112 | A fenced frame is the root of the fenced frame tree. The root fenced frame and any child iframes in this tree are not allowed to use communication channels to talk to frames outside the tree or vice-versa. The frames within the tree can communicate with each other normally. 113 | 114 | ### Information channel between fenced frame and other frames 115 | 116 | There are many channels between the fenced frame tree and the other frames that will need to be restricted and a few of them are listed below: 117 | 118 | 119 | 120 | * PostMessage 121 | * Name, allow, cspee and other attributes 122 | * Resize 123 | * Access to window.parent/ window.top etc. 124 | * Events fired simultaneously in the embedding context and the fenced frame such as page lifecycle events like onload 125 | * … 126 | 127 | This discussion assumes that third-party cookies, like all other third party storage, are also [disallowed](https://blog.chromium.org/2020/01/building-more-private-web-path-towards.html) or else those would be a communication channel between the fenced frame and the embedding site. 128 | 129 | ### HTMLFencedFrameElement class 130 | 131 | All fenced frame related functions will live in its own class, in the same way that iframe-related funcionality lives in HTMLIFrameElement. 132 | 133 | #### Can Load API 134 | 135 | There are various reasons a fenced frame config with an opaque url could refuse to load in a page. For example, if the page is not in a secure context, or if CSPEE is specified in the embedding frame, the fenced frame config will refuse to load. This is a lot for a developer to keep track of. 136 | 137 | If the process of getting an ad in the page is complex or expensive, there needs to be a way to ensure that the resulting ad will actually end up in the page before the expensive process begins. 138 | 139 | A static API method will be introduced to the HTMLFencedFrameElement class to check this. No fenced frame will be created when calling this API, and it can be invoked before actually attempting to load a fenced frame config. The API will return a boolean, true if a config with an opaque mapped url would be able to load in the caller's context, false if not. 140 | 141 | ##### Example usage 142 | 143 | ``` 144 | HTMLFencedFrameElement.canLoadOpaqueURL(); 145 | ``` 146 | ``` 147 | > true 148 | ``` 149 | 150 | This is called synchronously, and will look at the execution context of the frame invoking the API. 151 | 152 | ## Security considerations 153 | 154 | Even though a fenced frame is isolated from its embedding context, it cannot be used as a workaround to the security restrictions that the top-level site wants to enforce on the embedding frames, without the knowledge of the top-level site. The design decisions of fenced frames related to security mechanisms like sandbox, csp, permission policy etc. are based on the following principles: 155 | * Attributes like cspee, sandbox etc. and headers like frame-ancestors etc. cannot be used as a communication channel with the embedding context. 156 | * Fenced frame should not be able to escalate privileges without the knowledge of the top-level site. A feature disallowed by a top-level site for a given origin cannot be allowed in a fenced frame of that same origin, since that becomes a security risk. Since this requires the fenced frame learning about what features are allowed for its origin, and since revealing to the fenced frame what features are enabled for what origins are a fingerprinting vector, all permission policy delegation based features are therefore disallowed in fenced frames that don't allow data infiltration. Fenced frames that do allow for data infiltration (i.e. ones loaded with transparent URLs allowing for arbitrary data to be added) can use and inherit permissions policy delegation for features. See: [Fenced frames: permissions and document policies](https://github.com/WICG/fenced-frame/blob/master/explainer/permission_document_policies.md). 157 | * There are headers from the fenced frame site that are not honored as they would in an iframe, e.g. frame-ancestors, due to being a privacy leak. This is the reason fenced frames need to be opted in by the site using the opt-in response header. 158 | 159 | More about security mechanisms are detailed in: 160 | * [Fenced frames and CSP](https://github.com/WICG/fenced-frame/blob/master/explainer/interaction_with_content_security_policy.md) 161 | * [Fenced frames and policies](https://github.com/WICG/fenced-frame/blob/master/explainer/permission_document_policies.md) 162 | * [Fenced frames and sandbox](https://docs.google.com/document/d/1RO4NkQk_XaEE7vuysM9LJilZYsoOhydfh93sOvrPQxU/edit?usp=sharing) 163 | 164 | **Secure contexts:** Fenced Frames are only allowed if all ancestor frames are [secure contexts](https://w3c.github.io/webappsec-secure-contexts/), the fenced frame's document is from a [potentially trustworthy URL](https://w3c.github.io/webappsec-secure-contexts/#potentially-trustworthy-url) and all subresources inside the FF will follow [mixed mode restrictions](https://web.dev/fixing-mixed-content/). 165 | 166 | **Inheritance for local resources:** Documents hosting [local](https://fetch.spec.whatwg.org/#is-local) resources inherit their [policy containers](https://html.spec.whatwg.org/multipage/origin.html#policy-container) from their initiator or parent document, however for fenced frames, no such inheritance will take place. Fenced frames hosting local Documents will have a fresh policy container as they were created with no initiator document, just like the first Document in a top-level browsing context created with no initiator document. 167 | 168 | **xsleaks:** In terms of cross site leak attacks, fenced frames is at least as secure as iframes are and better in some cases by default e.g. always having noopener, no joint history etc. For more details, the fenced frames xsleaks audit can be found [here](https://docs.google.com/spreadsheets/d/1YkQxcQlOd24XmSUQ8RpQU0zINYSTTih8drNibV0LIXE/edit?usp=sharing). 169 | 170 | **Process isolation:** Process isolation for fenced frames is detailed [here](https://github.com/WICG/fenced-frame/blob/master/explainer/process_isolation.md). 171 | 172 | 173 | ## Privacy considerations 174 | 175 | The fenced frame’s main goal is to improve privacy by disallowing communication with the embedder. There are however some attributes that might need to be shared between the two and their privacy impact needs to be carefully considered and mitigated, if possible. Some of these attributes are: 176 | 177 | 178 | * **Initial size and resize:** The API that generates a fenced frame config can pick the initial size that the fenced frame document sees, subject to whatever restrictions it deems necessary for its privacy model. If the initial size is fixed, then any changes the embedder attempts to make to the fenced frame's size will not be reflected inside of it. 179 | * **Intersection Observer:** See [Integration with web platform > Viewability](https://github.com/WICG/fenced-frame/blob/master/explainer/integration_with_web_platform.md#Viewability) for discussion of the privacy considerations for the Intersection Observer API. 180 | * **Delegated permissions:** [Permission delegation](https://www.chromestatus.com/feature/5670617353289728) restricts permission requests to the top-level frame. Since fenced frames are embedded contexts, they should not have access to permissions, even if they are treated as top-level browsing contexts. Delegation of permissions from the embedding context to the fenced frame is a data infiltration channel, and should be disallowed when the privacy story disallows data inflow. This is detailed further [here](https://github.com/WICG/fenced-frame/blob/master/explainer/permission_document_policies.md). 181 | * **Network side channel:** This is detailed more here: [network side channel](https://github.com/WICG/fenced-frame/blob/master/explainer/network_side_channel.md) 182 | * **Navigation url:** Since fenced frames are allowed to open popups or navigate the top-level page in some use cases, gated on user activation, the navigation url can carry bits of information out of the fenced frame tree. If the embedder and the destination are same-origin, the information in the url and embedder's info can be joined locally on navigation. This might need mitigations going forward (currently being brainstormed); we plan to add metrics to understand how often this happens in practice. Additionally, this is vulnerable to the network side channel as mentioned above if the embedding site and destination site are colluding (even when not same-origin)---though this is less concerning than for non-navigation network requests, since navigation is only allowed upon user interactions like clicks. 183 | 184 | More of these channels exist and the [integration with web platform](https://github.com/WICG/fenced-frame/blob/master/explainer/integration_with_web_platform.md) details them further. 185 | 186 | ### Ongoing technical constraints 187 | Fenced frames disable explicit communication channels, but it is still possible to use covert channels to share data between the embedder and embeddee, e.g. global socket pool limit (as mentioned in the [xsleaks audit](https://docs.google.com/spreadsheets/d/1YkQxcQlOd24XmSUQ8RpQU0zINYSTTih8drNibV0LIXE/edit?usp=sharing)), network side channel and intersection observer as described above, etc. Mitigations to some of these are being brainstormed. We also believe that any use of these known covert channels is clearly hostile to users and undermines web platform intent to the point that it will be realistic for browsers to take action against sites that abuse them. 188 | 189 | ## Parallels with Cross-site portals 190 | 191 | [Portals](https://wicg.github.io/portals/) allow for rendering of, and seamless navigation to, embedded content. 192 | 193 | If the embedded content is cross-site, the privacy threat of joining user identities on the two sites exists before the user ever engages with the portal. The privacy threat for portals is further detailed [here](https://github.com/WICG/portals#privacy-threat-model-and-restrictions). 194 | 195 | Portal is a separate element type than a fenced frame, but requires very similar restrictions in its communication with the embedding context as a fenced frame. It is thus likely that portals and fenced frames will converge on their cross-site tracking mitigations to a large extent. 196 | 197 | ## API alternatives considered 198 | 199 | Both of the alternatives given in this section are applicable only if fenced frames were a type of iframe. As already described in the document above, they have the downside of spec and browser implementation complexity as many iframe capabilities will need to be special-cased for fenced frames. 200 | 201 | #### Using iframe with document policy 202 | 203 | In this alternative approach the fenced frame is a nested browsing context with the communications restrictions placed on an iframe via a [document policy](https://github.com/w3c/webappsec-feature-policy/blob/master/document-policy-explainer.md). 204 | 205 | 206 | Example usage 207 | 208 | ``` 209 | 211 | ``` 212 | 213 | 214 | The embedding site sends the following header in the request when creating the fenced frame root frame: 215 | 216 | 217 | ``` 218 | Sec-Required-Document-Policy: fenced-frame-tree;root=true 219 | ``` 220 | 221 | 222 | The server then responds back using the following header if it complies with the restrictions (otherwise the document will fail to load with an error). 223 | 224 | 225 | ``` 226 | Document-Policy: fenced-frame-tree;root=true 227 | ``` 228 | 229 | The fenced frame tree’s root frame is created using the root parameter’s value as true while any frames nested within it is set by the browser as having the root param set to false, unless a nested fenced frame tree is created where the root parameter is again set to true. Both true and false values of the root parameter are considered of equal strictness and thus it is possible to continue a fenced frame tree or start a new one. 230 | 231 | 232 | Benefits 233 | 234 | 235 | 236 | * Able to work with the existing “iframe” element 237 | 238 | 239 | Downsides 240 | 241 | 242 | 243 | * Much more complex spec and browser implementation since many iframe features will need to be special-cased for fenced frames. 244 | 245 | There were other alternatives considered for the iframe approach like using feature policy or a new attribute, detailed later in this document. 246 | 247 | 248 | #### Using a new iframe attribute 249 | 250 | Another way that was considered for this primitive was to have a new iframe attribute, say “fenced frame”. 251 | 252 | 253 | ``` 254 | 255 | ``` 256 | 257 | 258 | Benefits 259 | 260 | 261 | 262 | * A single attribute defines the fenced frame so it is simpler to use by developers 263 | 264 | Downsides 265 | 266 | 267 | 268 | * Iframe already has existing configuration attributes like sandbox, allow and policy and adding a fourth would lead to complexity in terms of how they all interact among each other. 269 | 270 | #### Using Feature policy/Permission policy 271 | 272 | We considered using [feature policy](https://developers.google.com/web/updates/2018/06/feature-policy) attributes for network, storage and communication channels using the ‘allow’ keyword, instead of document policy. 273 | 274 | Benefits over using document policy 275 | 276 | 277 | 278 | * Does not need HTTP header exchange as in document policy 279 | 280 | Downsides 281 | 282 | 283 | 284 | * Feature policy’s objective is the delegation of powerful feature permissions to trusted origins while a fenced frame requires general features like inter-frame communication to be restricted on documents. 285 | * Since there is no HTTP header exchange there are more chances of site breakage due to restricting common features like inter-frame communications. 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | -------------------------------------------------------------------------------- /explainer/TAG_Security_Privacy_Questionnaire.md: -------------------------------------------------------------------------------- 1 | ### **TAG Security/Privacy Questionnaire** 2 | 3 | This section contains answers to the [W3C TAG Security and Privacy](https://w3ctag.github.io/security-questionnaire/) [Questionnaire](https://w3ctag.github.io/security-questionnaire/). 4 | 5 | 6 | 7 | 1. What information might this feature expose to Web sites or other parties, and for what purposes is that exposure necessary? 8 | 9 | Fenced frames can be viewed as a more private and restricted iframe. As such, the element does not inherently expose any new information to web sites or third parties. However, Fenced Frames are intended to contain data that belongs to a partition other than the top-frame’s storage partition e.g. the rendering url in [TURTLEDOVE](https://github.com/w3ctag/design-reviews/issues/723) reflects the interest group of the user which may be derived from user activity in another partition. Therefore it is necessary for the Fenced Frame to attempt to block communications between the fenced frame and its embedder. Fenced frames remove explicit web-platform communication channels between the two (such as postMessage) and many side channels e.g. size, programmatic focus, policy delegation etc. but some side channels still exist and we will continue to work to mitigate them. 10 | 11 | 2. Do features in your specification expose the minimum amount of information necessary to enable their intended uses? 12 | 13 | Yes, see above answer for ways information exposure is minimized. 14 | 15 | 3. How do the features in your specification deal with personal information, personally-identifiable information (PII), or information derived from them? 16 | 17 | Fenced frames do not inherently provide personal information, PII or information derived from them. 18 | 19 | 4. How do the features in your specification deal with sensitive information? 20 | 21 | Same answer as # 3. 22 | 23 | 5. Do the features in your specification introduce a new state for an origin that persists across browsing sessions? 24 | 25 | No. 26 | 27 | 6. Do the features in your specification expose information about the underlying platform to origins? 28 | 29 | No 30 | 31 | 7. Does this specification allow an origin to send data to the underlying platform? 32 | 33 | No 34 | 35 | 8. Do features in this specification allow an origin access to sensors on a user’s device 36 | 37 | No 38 | 39 | 9. What data do the features in this specification expose to an origin? Please also document what data is identical to data exposed by other features, in the same or different contexts. 40 | 41 | Same answer as #1. 42 | 43 | 10. Do features in this specification enable new script execution/loading mechanisms? 44 | 45 | No 46 | 47 | 11. Do features in this specification allow an origin to access other devices? 48 | 49 | No 50 | 51 | 12. Do features in this specification allow an origin some measure of control over a user agent’s native UI? 52 | 53 | No 54 | 55 | 13. What temporary identifiers do the features in this specification create or expose to the web? 56 | 57 | None. 58 | 59 | 14. How does this specification distinguish between behavior in first-party and third-party contexts? 60 | 61 | Fenced frames are always present as embedded frames. In terms of communication restrictions from the embedding page, they behave almost like a separate tab but fenced frames do not get access to first-party storage/cookies. A fenced frame document gets access to a nonce-based ephemeral cookie and storage partition. 62 | 63 | 15. How do the features in this specification work in the context of a browser’s Private Browsing or Incognito mode? 64 | 65 | No difference with a regular mode browser 66 | 67 | 16. Does this specification have both "Security Considerations" and "Privacy Considerations" sections? 68 | 69 | Yes. 70 | 71 | 17. Do features in your specification enable origins to downgrade default security protections? 72 | 73 | No 74 | 75 | 18. What should this questionnaire have asked? 76 | 77 | N/A 78 | -------------------------------------------------------------------------------- /explainer/fenced_frame_config.md: -------------------------------------------------------------------------------- 1 | # Fenced frame configs 2 | 3 | 4 | ## Introduction 5 | 6 | For use cases involving APIs that access cross-site data, we need to be able to load a fenced frame with content determined by the API without revealing information about the content to the embedding context. For example, with interest-based ads in [Protected Audience](https://github.com/WICG/turtledove), the winning ad that's returned from the auction depends on the user's cross-site interest group data, which we don't want to expose to the site that calls the auction. This document proposes a web-platform way of loading content into a fenced frame using an opaque object. 7 | 8 | 9 | ## Proposed solution 10 | 11 | `` has an attribute `config`, rather than `src`. APIs like FLEDGE return a `FencedFrameConfig` object defined by our [WebIDL](https://wicg.github.io/fenced-frame/#fenced-frame-config-interface). This object has a series of fields that specify the behavior desired by the API (e.g. the ad url, width and height as seen from within the fenced frame, etc.). When the embedder stores this object into the `config` attribute, the fenced frame loads the context accordingly. 12 | 13 | In order to hide information as described above, the browser _redacts_ `FencedFrameConfig` before sending it to the embedder. This means that certain fields which are sensitive, like the ad url, are replaced with a string `opaque`. The embedder may see whether there is a value defined for that field, but not what the value is. Likewise, when the embedder requests that a config be loaded into the fenced frame, the browser is responsible for looking up the config in a data structure in order to access the unredacted information. 14 | 15 | 16 | ### Protected Audience Example 17 | 18 | When the SSP JS invokes the Protected Audience API to run the ad auction, it gets back the `FencedFrameConfig` as the result, which is then used for rendering the fenced frame. This `FencedFrameConfig` has an opaque `src`, which maps to an actual ad url which is part of the interest group. 19 | 20 | 21 | ``` 22 | navigator.runAdAuction(myAuctionConfig).then((auctionWinnerConfig) => { 23 | // auctionWinnerConfig value e.g. 24 | // FencedFrameConfig { 25 | // 'src': 'opaque' ('ad.com/foo' internally) 26 | // ... 27 | // } 28 | const adFrame = document.createElement('fencedframe'); 29 | adFrame.config = auctionWinnerConfig; 30 | }); 31 | ``` 32 | 33 | ## Backwards compatibility 34 | 35 | Previously we used a [`urn:uuid`](https://tools.ietf.org/html/rfc4122) and the `src` attribute to accomplish this same behavior. We will continue to support `urn:uuid` and `src` for a transition period. 36 | Update: The `src` attribute is no longer supported on fenced frames. 37 | 38 | ## Embedder context 39 | 40 | After creating the config and prior to loading the config into the fenced frame, an embedder can communicate a string of contextual information to one or more worklets for the [Shared Storage API](https://github.com/WICG/shared-storage) that are spun up inside the fenced frame (details [here](https://github.com/WICG/fenced-frame/blob/master/explainer/fenced_frame_config_context.md)). This can be useful for reporting purposes. 41 | -------------------------------------------------------------------------------- /explainer/fenced_frame_config_context.md: -------------------------------------------------------------------------------- 1 | # Embedder context in fenced frame configs 2 | 3 | ## Introduction 4 | 5 | For use cases that leverage the [Private Aggregation API](https://github.com/patcg-individual-drafts/private-aggregation-api) to report on advertisements within fenced frames, it might be important to tie certain information available inside the fenced frame, e.g. viewability or performance, to some contextual information from the embedding publisher page, such as an event-level ID. 6 | 7 | In a scenario where the input URLs for the fenced frame are required to be k-anonymous, however, such as when creating a [FencedFrameConfig](https://github.com/WICG/fenced-frame/blob/master/explainer/fenced_frame_config.md) from running a [FLEDGE auction](https://github.com/WICG/turtledove/blob/main/FLEDGE.md#2-sellers-run-on-device-auctions), trying to communicate the event-level ID to the fenced frame by attaching an identifier to any of the input URLs would make it difficult for any input URL(s) with the attached identifier to reach the k-anonymity threshold. 8 | 9 | ## Proposed solution 10 | 11 | Instead, before navigating the fenced frame to the auction's winning [FencedFrameConfig](https://github.com/WICG/fenced-frame/blob/master/explainer/fenced_frame_config.md), the embedder could write the event-level ID, or other contextual information, as a string, by using the [FencedFrameConfig](https://github.com/WICG/fenced-frame/blob/master/explainer/fenced_frame_config.md)'s `setSharedStorageContext()` method, as in the example below. 12 | 13 | Subsequently, anything written through the [FencedFrameConfig](https://github.com/WICG/fenced-frame/blob/master/explainer/fenced_frame_config.md)'s `setSharedStorageContext()` method prior to a fenced frame's navigation to that config, can be read via `sharedStorage.context` from inside a worklet for the [Shared Storage API](https://github.com/WICG/shared-storage) created by the fenced frame or by any of its same-origin descendants. That is, `sharedStorage.context` can be invoked via the script for a operation previously registered through [`sharedStorage.worklet.addModule()`](https://github.com/WICG/shared-storage/tree/main#outside-the-worklet) and then called by [`sharedStorage.run()`](https://github.com/WICG/shared-storage/tree/main#outside-the-worklet). 14 | 15 | ## Example 16 | 17 | After the SSP's JavaScript invokes the [Turtledove/FLEDGE API](https://github.com/WICG/turtledove/blob/main/FLEDGE.md) and receives the resulting [FencedFrameConfig](https://github.com/WICG/fenced-frame/blob/master/explainer/fenced_frame_config.md) `fencedFrameConfig`, the SSP JS can write an event ID string via `fencedFrameConfig.setSharedStorageContext()`. 18 | 19 | In the embedder page: 20 | 21 | ```js 22 | // See https://github.com/WICG/turtledove/blob/main/FLEDGE.md for how to write an auction config. 23 | const auctionConfig = { ... }; 24 | 25 | // Run a FLEDGE auction, setting the option to "resolveToConfig" to true. 26 | auctionConfig.resolveToConfig = true; 27 | const fencedFrameConfig = await navigator.runAdAuction(auctionConfig); 28 | 29 | // Write to the config any desired embedder contextual information as a string. 30 | fencedFrameConfig.setSharedStorageContext("My Event ID 123"); 31 | 32 | // Navigate the fenced frame to the config. 33 | document.getElementById('my-fenced-frame').config = fencedFrameConfig; 34 | ``` 35 | 36 | The reporting JavaScript in the fenced frame would spin up a [shared storage worklet](https://github.com/WICG/shared-storage#in-the-worklet-during-an-operation), in order to make a report about some information `frameInfo` that is only available within the fenced frame, and that needs to be tied back to the event ID string for reporting purposes. 37 | 38 | In the fenced frame (`my-fenced-frame`): 39 | 40 | ```js 41 | // Save some information we want to report that's only available inside the fenced frame. 42 | const frameInfo = { ... }; 43 | 44 | // Create a shared storage worklet. 45 | // See https://github.com/WICG/shared-storage#proposed-api-surface for more details 46 | // about creating and running shared storage worklets. 47 | await window.sharedStorage.worklet.addModule('report.js'); 48 | 49 | // Send a report using shared storage and private aggregation. 50 | await window.sharedStorage.run('send-report', { 51 | data: { info: frameInfo }, 52 | }); 53 | ``` 54 | 55 | Inside the [shared storage worklet](https://github.com/WICG/shared-storage#in-the-worklet-during-an-operation) itself, the event ID can be retrieved and sent in a aggregatable report via the [Private Aggregation API](https://github.com/patcg-individual-drafts/private-aggregation-api). 56 | 57 | In the worklet script (`report.js`): 58 | 59 | ```js 60 | // See https://github.com/WICG/shared-storage#in-the-worklet-during-addmodule for more 61 | // details about registering shared storage operations. 62 | class ReportingOperation { 63 | async run(data) { 64 | // Helper functions that map the event ID to a predetermined bucket and the frame info 65 | // to an appropriately-scaled value. 66 | // See also https://github.com/patcg-individual-drafts/private-aggregation-api#examples 67 | function convertEventIdToBucketId(eventId) { ... } 68 | function convertFrameInfoToValue(info) { ... } 69 | 70 | // The user agent sends the report to the reporting endpoint of the script's 71 | // origin (that is, the caller of `sharedStorage.run()`) after a delay. 72 | privateAggregation.sendHistogramReport({ 73 | bucket: convertEventIdToBucketId(sharedStorage.context) , 74 | value: convertFrameInfoToValue(data.info) 75 | }); 76 | } 77 | } 78 | register('send-report', ReportingOperation); 79 | ``` 80 | -------------------------------------------------------------------------------- /explainer/fenced_frames_with_local_unpartitioned_data_access.md: -------------------------------------------------------------------------------- 1 | # **Fenced Storage Read API** 2 | **(earlier referred to as Fenced Frames with local unpartitioned data access)** 3 | 4 | 5 | ## Introduction and Goals 6 | 7 | There are situations in which it is helpful to decorate a third-party widget with cross-site information about the user, such as a personalized payment button that displays credit card information to give the user confidence that the payment flow will be smooth, or a personalized sign-in button. Showing a personalized button gives the user more context about what they can expect will happen when they click on the button, allowing them to make a more informed choice, closer to their preferences. These sorts of use cases will be broken in scenarios when [third-party cookies are not available](https://privacysandbox.com/news/privacy-sandbox-update/). 8 | 9 | Fenced frames are a natural fit for such use cases, as they allow for frames with cross-site data to be composed within a page of another partition. The idea proposed here is to allow fenced frames to have access to the cross-site data stored for the given origin within [shared storage](https://github.com/WICG/shared-storage). In other words, the payment site would add the user’s payment data to shared storage when the user visits the payment site, and then read it in third-party fenced frames to decorate their payment button. 10 | 11 | To prevent the fenced frame from leaking the user’s shared storage data out (to the embedder or to servers via network) we’re requiring that fenced frames first disable all untrusted network[1] communications before accessing shared storage. Note that the eventual intent is that all fenced frames would disable untrusted network communication anyway, so this isn’t exactly new, but it’s particularly vital that we do so when allowing access to shared storage since it has unbounded cross-site information available to it, compared to e.g. k-anonymous cross-site information available in Protected Audience ads. 12 | 13 | The motivation for this variant of fenced frames are customized payment buttons for third-party payment service providers (as discussed in this [issue](https://github.com/WICG/fenced-frame/issues/15)) but this proposal is not intended to be restricted to payments. Any form of third-party UX that wishes to show personalized information to a user, without leaking that information to the embedder, could use it. 14 | 15 | [1] More details [below](#why-untrusted-network) on untrusted vs trusted network 16 | 17 | 18 | ## User experience 19 | 20 | It’s been [noted](https://developers.googleblog.com/2021/05/updated-google-pay-button-increases-click-through-rates.html) that personalized payment buttons (buttons that display saved payment methods) can significantly increase click-through rates as it provides increased confidence that the checkout flow will be smooth. With this proposal, users will continue to see the personalized button. 21 | 22 | ## Information flow and design 23 | 24 | The sequence of steps to achieve the user experience as mentioned above are given below: 25 | 26 | 27 | 28 | 1. **Same as today:** A user visits the payment provider’s site as a first party and enters their payment method details, for later use on merchant sites. 29 | 2. **New:** After step 1, the payment provider decides what information is needed from the user's payment method details to render in a subsequent personalized button and writes it to shared storage (reasons for selecting shared storage discussed [here](#shared-storage-access)). For example, if the user details needed in the personalized payment button are the last 4 digits of the user’s credit card, the JS on the payment provider’s page will invoke the following: 30 | 31 | ``` 32 | window.sharedStorage.set("last-4-digits", value) 33 | ``` 34 | 35 | 36 | 3. **Same as today:** The user, at a later time, visits the merchant’s site and the payment provider’s script, say, payment.js, on the merchant site decides to create a personalized button. Note that payment.js runs on the merchant’s page, either directly on the 1p page or in an iframe belonging to the payment provider. 37 | 4. **New:** For creating the personalized button, payment.js creates a fenced frame instead of an iframe as it does today, using the following FencedFrameConfig constructor: 38 | 39 | ``` 40 | fenced_frame = new FencedFrameConfig('https://examplepay.com/button.html?'); 41 | ``` 42 | 43 | 44 | 45 | **Privacy impact:** Note that it is ok for the source of the fenced frame to carry arbitrary data from the creator context because that data cannot be joined with cross-site data until after the network is restricted. 46 | 47 | 5. **New: State 1 of the fenced frame (full network):** In this state, when the fenced frame is created, it doesn’t have any unpartitioned data access. The fenced frame in this state has unrestricted network access which can be utilized to load the HTML document and subresources in the fenced frame (such as the button image). 48 | 49 | Note that in this state the content in the fenced frame is not personalized, since it hasn’t accessed any unpartitioned data. 50 | 51 | 6. **New: State 2 of the fenced frame (disable untrusted network):** In order to access unpartitioned data to personalize the contents of the fenced frame, the fenced frame needs to block off network access. As mentioned above in the privacy impact section this will prevent any data joined across the embedding site and the fenced frame site from exfiltrating. There will be a new API introduced to do that: `window.fence.disableUntrustedNetwork();` 52 | 7. **New: State 2 of the fenced frame (access unpartitioned data):** Finally after exfiltration channels have been blocked off via window.fence.disableUntrustedNetwork(), the FF content can access unpartitioned data via shared storage. The data that was written to shared storage in step 2, can now be read and rendered to personalize the content via the `sharedStorage.get()` method. 53 | 54 | There we go: the user now sees the personalized button!! 55 | 56 | 57 | 58 | 8. **Same as today:** If the user wants to proceed with the payment transaction, they can click on the button. 59 | 9. **New:** To proceed with the payment transaction, payment.js needs to be able to listen to the click that happened on the button via the new click API surface described [here](#click-listener-api). 60 | 10. **Same as today:** Once the information that a click happened inside the FF is available in the embedding context, the payment.js opens a new top-level context as a new tab or invokes the [Payment Handler API](https://developer.mozilla.org/en-US/docs/Web/API/Payment_Handler_API) and the transaction proceeds as it does today. 61 | 62 | 63 | ## Shared Storage Access 64 | 65 | This section goes into why we chose shared storage for this solution. We considered alternatives like Cookies and Local Storage as described in the “Alternatives considered” section. 66 | 67 | 68 | ### **Data Requirements** 69 | 70 | Let’s first go through the requirements on the data, taking the example of examplepay.com as the payment provider: 71 | 72 | 73 | 74 | * **Readability**: The data needs to be readable in an examplepay.com fenced frame (after untrusted network has been revoked) and not in an examplepay.com top-level frame or iframe. 75 | * The data only needs to be read inside the FF from JS and not via network headers. 76 | * **Writability**: The data only needs to be writable in a 1p context from examplepay.com. 77 | * **Scope:** The data should be scoped to the origin examplepay.com. 78 | * **Size:** As per the current use case feedback, the data itself is not very large, is text-only and can fit in a normal cookie size. This is subject to change though, e.g. if a payment provider wants to also show the user's profile picture in the personalized button. 79 | * **Unpartitioned:** The data only needs to be accessed in the unpartitioned state and not in a partitioned (by top-level site i.e. the merchant site for payment providers) state. 80 | 81 | Shared Storage is a Privacy Sandbox API that allows unpartitioned storage access with restricted output gates as described [here](https://github.com/WICG/shared-storage/blob/main/README.md). The existing output gates for shared storage are private aggregation report and opaque URL selection. The proposal here is to introduce a new output gate: **read from a fenced frame after network revocation**. 82 | 83 | Some of the enhancements needed for shared storage to be used for this proposal are: 84 | 85 | 86 | 87 | * Create a new shared storage output gate: a fenced frame with no network. Privacy-wise this is safe, since the unpartitioned data being read is not exfiltrated either to the embedding context (because of the nature of fenced frames) or via writing to any unpartitioned storage (like local storage, since FFs have a unique, ephemeral storage partition) or via network. 88 | * The API `sharedStorage.get('')` will need to be enabled inside the fenced frame and can only resolve successfully once the network is cut-off. 89 | 90 | Note that there is no change needed to Shared Storage write mechanisms, since it is already writable from both 1p and 3p contexts and this use case only needs 1p write access. 91 | 92 | **Benefits** 93 | 94 | The benefits of using shared storage for this solution are primarily how it aligns with all of the requirements mentioned above. 95 | 96 | 97 | 98 | * The incremental enhancements to shared storage for this use case aren’t complicated/hard to integrate in the existing shared storage design/implementation. 99 | * Shared storage, is by definition, unpartitioned data. There is no notion of partitioned data for this use case as mentioned in the Requirements section above, which makes it more aligned with using shared storage. 100 | * Shared storage is by JS-readable only and thus aligns with the requirement. 101 | * Additionally, the invocation of Shared Storage get() API for this feature is gated behind [enrollment and attestation](https://developers.google.com/privacy-sandbox/private-advertising/enrollment) which offers additional, policy-based, privacy protection. Note a new enrollment and attestation category will be added specifically for accessing unpartitioned data within the fenced frame tree named “Fenced Storage Read API”. 102 | 103 | **Downsides** 104 | 105 | 106 | 107 | * Browser compatibility: Even though other browsers should not see concerns with the privacy aspect of this output gate of shared storage, it’s more work to implement for other browsers than exposing cookies or localStorage to a fenced frame since they haven’t implemented shared storage yet. See the LocalStorage section to see mitigations for this. 108 | 109 | 110 | ## Revoking Network Access 111 | 112 | At a high level, the new API window.fence.disableUntrustedNetwork() allows a fenced frame to disable exfiltrating information (primarily via network requests) in exchange for gaining access to unpartitioned data via sharedStorage reads. 113 | 114 | Some more details: 115 | 116 | 117 | 118 | * Even though this information flow only relies on fenced frames created using the url constructor, we would not be disallowing the usage of window.fence.disableUntrustedNetwork() in FFs created using the other APIs as the eventual intent is for all fenced frames to have restricted network access. It will be available from fenced frames whose configs are generated by all current methods: 119 | * navigator.runAdAuction(...) 120 | * sharedStorage.selectURL(...) 121 | * FencedFrameConfig(url) 122 | * As a result of invoking this API, network is disabled in the complete fenced frame tree, i.e. in the root fenced frame and any of its embedded iframes. 123 | * We are still thinking about how disableUntrustedNetwork() should interact with nested fenced frames. The alternatives are: 124 | * Any embedded fenced frames within the parent FF should also have invoked disableUntrustedNetwork() before the parent FF can access shared storage. 125 | * Calling disableUntrustedNetwork() disables network for all child fenced frames. 126 | * Disabling network disables the following: 127 | * **Subresources requests**: This includes resource requests like for scripts, images etc. or APIs like sendBeacon, etc. 128 | * **Navigation requests:** This implies that there cannot be a navigation initiated either for loading a document inside the FF tree or for navigating the top-level page or opening a new tab/window. 129 | * **Event level reporting:** Any event level reporting mechanisms supported in fenced frames, i.e., [fenced frames ads reporting](https://github.com/WICG/turtledove/blob/main/Fenced_Frames_Ads_Reporting.md). 130 | * **Any other network channels:** This includes any channel not covered in the above categories like WebSocket, web workers, etc. 131 | * **In-progress network requests:** Allowing in-progress network requests to continue could lead to inadvertent privacy leaks. For example, a possible attack could arise where multiple requests are initiated and, based on unpartitioned data, some of them are canceled via the [abort API](https://developer.mozilla.org/en-US/docs/Web/API/AbortController). Therefore the proposal is to cancel any ongoing requests. 132 | * This implies that disableUntrustedNetwork() should only be invoked when the critical resources have been fetched completely, such as by listening to the[ load event](https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event). 133 | * The API design to handle in-progress requests is currently under discussion. 134 | 135 | 136 | ### Why “untrusted” network 137 | 138 | Certain privacy preserving aggregated reports can be allowed from the fenced frame after disableUntrustedNetwork() has been invoked. After the untrusted network access has been revoked, with the correct permission policies, the fenced frame should be able to invoke APIs like the [Private Aggregation API](https://developer.chrome.com/docs/privacy-sandbox/private-aggregation/#what-is-the-private-aggregation-api) which allows aggregated data to be sent out on the network as that inherently disallows any arbitrary data exfiltration. There may be additional trusted network communications in the future, such as to a secure trusted execution environment. 139 | 140 | 141 | ## Click listener API 142 | 143 | The click listener API is broken into two parts: 144 | 145 | * The embedding context will invoke `addEventListener()` on the `HTMLFencedFrameElement` to listen for a click event on the fenced frame. 146 | * A script inside the fenced frame tree will invoke a new method on `window.fence`, which will trigger the embedding context’s click event listener. 147 | 148 | ### Changes to HTMLFencedFrameElement 149 | 150 | After a fenced frame element object is created, the embedder can call `addEventListener(‘fencedtreeclick’, callback)` on it to attach an event listener to the frame. The new listener can fire when an event with type `click` is fired in the embedded document’s DOM tree. A new [event handler](https://html.spec.whatwg.org/multipage/webappapis.html#event-handler-attributes) named `onfencedtreeclick` will also be exposed on all HTML elements, Document objects, and Window objects, to allow fenced frames' parent elements to listen for `fencedtreeclick` events via the `onfencedtreeclick` attribute as well. 151 | 152 | To start, the spec will only support `fencedtreeclick`, but given that this API relies on the existing DOM event listener specification, it would be trivial to support other `fencedtree*` events in the future. 153 | 154 | The `fencedtreeclick` event listener callback will receive an event object, but it will contain the minimal amount of information necessary to handle the event. Specifically, it will obey the following rules: 155 | 156 | * It will be fired using the base DOM Event constructor, rather than a new event subclass. 157 | * It will be initialized with a type parameter of `'fencedtreeclick'` 158 | * All instances of the event object will be initialized with the same static timestamp value in order to mitigate timing side-channel attacks. The timestamp value of the DOM Event interface is a duration represented by `DOMHighResTimeStamp`, 159 | so user agents can choose a suitable value to use, such as the Unix epoch. 160 | * The event's `isTrusted` field will be true, to indicate that the event is dispatched by the user agent. 161 | * All other attributes of the event object will have the default settings of a newly-constructed event object. 162 | * When the event object is dispatched, its target will always be the `HTMLFencedFrameElement` upon which the event listener was registered. 163 | 164 | Note that specific click information like mouse coordinates are not included. These rules ensure that the event object doesn’t leak information from or about the embedded content. 165 | 166 | ### Changes to window.fence 167 | 168 | Once the embedder has registered the `fencedtreeclick` handler on the fenced frame element, the event needs to be fired while handling the corresponding `click` event within the frame’s content document. This will occur via a new method on the `window.fence` interface, `window.fence.notifyEvent(triggering_event)`. This is different from the existing `reportEvent()` method: 169 | 170 | * `reportEvent()` communicates data about events to a remote URL, and the corresponding beacon also includes data set via `registerAdBeacon` (called by Protected Audience worklets) in the destination URL. See the [Protected Audience API explainer](https://github.com/WICG/turtledove/blob/main/Fenced_Frames_Ads_Reporting.md#reportevent-preregistered-destination-url) for more details. 171 | * `notifyEvent()` communicates that an event occurred to the embedder, and nothing else. No extra information is added to the event. This API call also acts as an opt-in by the fenced frame document’s origin to allow sending the notification to the embedding site. 172 | 173 | The function takes one argument, `triggering_event`, which is a `click` event object that the frame’s content is currently handling. In order to trigger the `fencedtreeclick` event in the embedder, this object’s `isTrusted` field must be true, the event must currently be dispatching, and the event’s type name must be `click`. These requirements guarantee that the `fencedtreeclick` event will only be fired by user-agent-generated click events in response to user actually clicking as opposed to a script-generated event. 174 | 175 | Here's an example of how `window.fence.notifyEvent()` should be used: 176 | 177 | ```javascript 178 | // In the embedder: 179 | 180 | // Make a fenced frame 181 | let fencedframe = ... 182 | 183 | fencedframe.addEventListener('fencedtreeclick', () => { 184 | alert('hello world!'); 185 | }); 186 | 187 | // In the embedded content: 188 | 189 | document.body.addEventListener('click', (e) => {} { 190 | // Fire a "fencedtreeclick" event at the embedder. 191 | window.fence.notifyEvent(e); 192 | }); 193 | ``` 194 | 195 | The `notifyEvent()` method will not be available in iframes (same-origin or cross-origin), and will only be available in the fenced frame root’s document. 196 | 197 | ### Click Privacy considerations 198 | 199 | Since this is exfiltrating some information (that a click happened) outside the fenced frame, we will need to consider the following privacy considerations: 200 | 201 | * A possible attack using multiple fenced frames: an embedder creates `n` fenced frames, which all disable network and then determine (by predetermined behavior, or through communication over shared storage) which one of them should display nonempty content. Then if a user clicks on the only nonempty fenced frame, this exfiltrates log(n) bits of information through the click notification. Mitigating this will require some rate limits on the number of fenced frames on a page that are allowed to read from shared storage. This is similar to [shared storage’s existing rate limits](https://github.com/WICG/shared-storage#:~:text=per%2Dsite%20(the%20site%20of%20the%20Shared%20Storage%20worklet)%20budget). 202 | * Click timing could be a channel to exfiltrate shared storage data, but it’s a relatively weak attack since it requires user gesture and is therefore non-deterministic and less accurate. In addition, as a policy based mitigation, shared storage APIs’ invocation will be gated behind [enrollment](https://developer.chrome.com/en/docs/privacy-sandbox/enroll/). 203 | * One potential concern around the `notifyEvent()` API shape is that a single trusted `click` event could be cached by the JS running in the fenced frame and reused in additional `notifyEvent()` calls. However, the requirement that the trusted event *must be dispatching* mitigates this concern. Once the dispatch initiated by the browser completes, `notifyEvent()` will no longer accept the cached event object. If JavaScript on the page then tries to manually re-dispatch the cached event, the object will no longer be trusted (its `isTrusted` field will be set to false). 204 | 205 | ### User Activation 206 | 207 | When a user clicks on a fenced frame, the fenced frame window will have [user activation](https://developer.mozilla.org/en-US/docs/Web/API/UserActivation). User activation is frequently used to [gate access](https://developer.mozilla.org/en-US/docs/Web/Security/User_activation) to powerful Web Platform features unless the user has interacted with the page. In response to a click on a fenced frame, the embedder might want to use one of these features. For example, a personalized third-party payment button is rendered in a fenced frame, and when it’s clicked the first-party merchant site then engages their payment flow. This might involve opening a new window via `window.open()`, or using the `PaymentRequest` API directly, both of which are gated on the transient form of user activation. However, fenced frames don’t automatically propagate user activation to their embedder in the same way that other frames propagate it to their parent. This means that `window.fence.notifyEvent()` has to provide user activation to the embedder manually. 208 | 209 | When `window.fence.notifyEvent(triggering_event)` is called in the fenced frame, three actions will occur related to user activation: 210 | 211 | 1. First, we’ll ensure that the fenced frame currently has *transient* activation. If all of the requirements on `triggering_event` are met (as described [above](#changes-to-windowfence)), this will likely be true already, but it still must be confirmed explicitly. 212 | 2. Transient activation will be consumed in the fenced frame. This is to ensure that only one transient-activation-gated API can be used in response to a single click, and the fenced frame is delegating that one API call to its embedder. 213 | 3. An [activation notification](https://html.spec.whatwg.org/multipage/interaction.html#activation-notification) will be applied in the embedding frame, so that it may call an activation-gated API instead of the fenced frame. The embedding frame will receive both *transient* and *sticky* user activation. 214 | 215 | Transient activation will expire after a set amount of time if it is not consumed by a relevant API (in Chromium, this value is 5 seconds). An embedder document and a fenced frame document could cooperate in an attempt to extend this timeout, by waiting to call `notifyEvent()` until immediately before the expiration time. This would give the embedder an additional few seconds to use an activation-gated API. However, because `notifyEvent()` consumes transient activation in the fenced frame, this still only allows a single transient-activation-gated API call to be made. 216 | 217 | ## Code Example 218 | 219 | Now let's take a look at how shared storage, revocation of untrusted network access, and the click listener API can be combined in a real-world example. 220 | 221 | This example demonstrates how a third-party payment provider (examplepay.com) might embed a personalized payment button onto a merchant's site. First, the payment provider stores card information in shared storage when a user visits their site in a first-party context. Later, a merchant site uses the provider's API to embed a personalized button, which is rendered in a fenced frame. The fenced frame disables untrusted network access, reads the card information from shared storage, and sets up a click handler on the button to initiate the payment flow. 222 | 223 | ```javascript 224 | // When a user navigates to “examplepay.com” and registers their credit card, the last 225 | // four digits of their card are written to Shared Storage. 226 | 227 | // On https://examplepay.com 228 | async function registerCard() { 229 | // Prepare HTTP request with user-provided card infomation. 230 | let request = createCardRegistrationRequest({number: 'XXXX XXXX XXXX 1234', 231 | expDate: 'MM/YY', ...}); 232 | 233 | // Register the card information with examplepay.com. 234 | let response = await fetch(request); 235 | 236 | // If the card was registered successfully, write the last 4 digits of the 237 | // card number to Shared Storage for origin "examplepay.com." The data to 238 | // write could come from the response body, a 1p cookie in a response header, 239 | // or somewhere else. 240 | if (response.status === 200) { 241 | let body = await response.json() 242 | await window.sharedStorage.set('last4', body.last4); 243 | console.assert(body.last4 === '1234'); 244 | } 245 | } 246 | 247 | // Once the value has been written to Shared Storage, it can later be read inside a 248 | // fenced frame, but only when that frame is same-origin to examplepay.com and has 249 | // its network access restricted. Here’s what that would look like on a merchant page: 250 | 251 | // On merchant page 252 | let example_pay_button = examplePayAPI.createButton(); 253 | document.body.appendChild(example_pay_button); 254 | 255 | // In examplePayAPI 256 | function createButton() { 257 | let fenced_frame = document.createElement('fencedframe'); 258 | // Create a fenced frame config using a URL directly instead of a config-generating 259 | // API like Protected Audience or sharedStorage.selectURL(). Note that the URL is 260 | // same-origin to the site where the card was first registered. 261 | fenced_frame.config = new FencedFrameConfig('https://examplepay.com/make_button'); 262 | 263 | // Registering a "fencedtreeclick" event handler on the fenced frame element allows 264 | // it to respond to a "click" event that fires inside the frame's content. 265 | fenced_frame.addEventListener('fencedtreeclick', () => { 266 | startPaymentFlow(); 267 | }); 268 | return fenced_frame; 269 | } 270 | 271 | // In the "https://examplepay.com/make_button" fenced frame document 272 | function personalizeButton () { 273 | // By waiting for the page to finish loading, we can ensure that there's 274 | // no additional JS waiting to execute before revoking network. 275 | window.onload = async () => { 276 | // First, disable untrusted network access in the fenced frame. 277 | await window.fence.disableUntrustedNetwork(); 278 | 279 | // Read the last four digits of the card from Shared Storage 280 | // and render them in a button. 281 | b = document.createElement('button'); 282 | b.textContent = await window.sharedStorage.get('last4'); 283 | 284 | // Tell the embedder that the button was clicked, so that the payment flow can be 285 | // initiated. This will fire a "fencedtreeclick" event at the fenced frame element 286 | // in the embedder, which we previously registered a handler for. 287 | b.addEventListener('click', (e) => { 288 | window.fence.notifyEvent(e); 289 | }); 290 | 291 | document.body.appendChild(b); 292 | } 293 | } 294 | ``` 295 | 296 | ## Try it yourself! 297 | 298 | Development of this feature is ongoing, but the core functionality described above is implemented in Chromium and can be enabled with two command line flags. **We recommend using Chrome Canary to test with our most recent changes.** 299 | 300 | * `--enable-features=FencedFramesDefaultMode,FencedFramesLocalUnpartitionedDataAccess` 301 | * `--disable-features=EnforcePrivacySandboxAttestations` 302 | 303 | We also have some Glitch demo sites for testing the personalized payment button use case. 304 | 305 | * First, visit [demo-payments-provider.glitch.me](https://demo-payments-provider.glitch.me) to register credit card info (please don't use a real credit card number 🙂). 306 | * Then, visit [demo-merchant.glitch.me](https://demo-merchant.glitch.me) for a sample checkout experience with a personalized payment button. 307 | 308 | ## Privacy considerations 309 | 310 | This section goes into the privacy considerations of the 2 states a fenced frame can be in: 311 | 312 | **State 1 (before untrusted network is disabled):** In this state, the fenced frame has contextual information from the embedder site, but not cross-site data. This is equivalent to an iframe and has no privacy concerns. 313 | 314 | **State 2 (after untrusted network is disabled):** In this state, the fenced frame could join the user’s identity on the embedding site with the user’s identity on the fenced frame site, but the join is unable to be exfiltrated out. 315 | 316 | Click privacy considerations are already described in the [earlier section](#click-privacy-considerations). 317 | 318 | An additional element of user privacy is the ability to turn off this feature via a UX control. To achieve this, Chrome will disable this feature when the “Block third-party cookies” settings is enabled. UAs should ensure that users are able to control this capability in alignment with controls for similar cross-site storage capabilities. 319 | 320 | ### New Permissions Policy: fenced-unpartitioned-storage-read 321 | 322 | When a fenced frame accesses unpartitioned data like Shared Storage, a delegation of trust occurs between the embedding context and the fenced frame origin. If the embedder does not trust the content rendered in the fenced frame, it should be able to prevent script in the fenced frame from accessing unpartitioned data. We accomplish this via a new [Permissions Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Permissions_Policy) directive, which we call `fenced-unpartitioned-storage-read`. 323 | 324 | The `fenced-unpartitioned-storage-read` allowlist will default to `*`, similar to the [`shared-storage` permission](https://wicg.github.io/shared-storage/#permission). If an embedding site wants to restrict a fenced frame’s access to Shared Storage, it can do so by setting a stricter allowlist for that frame, such as `self` or a specific list of origins. 325 | 326 | ## Security considerations 327 | 328 | This new variant of fenced frames (constructed with a normal URL instead of a config or opaque URL) has similar [security considerations](https://github.com/WICG/fenced-frame/blob/master/explainer/README.md#security-considerations) to existing fenced frames but because this variant allows information to flow in from the embedding context to the fenced frame, things like permission delegation are simpler (discussed below). 329 | 330 | 331 | ### Permissions delegation 332 | 333 | Fenced frames constructed using the non-opaque URL constructor do not have to worry about bits of information being passed via permission delegation. Having said that, we cannot allow any permission based feature that would create a channel of communication in the reverse direction, i.e. from the fenced frame to the rest of the page, e.g. Fullscreen since a “fullscreenchange” event that originates from a fenced frame is observable by its embedder. Another factor to consider is not allowing features that are 334 | 335 | 336 | 337 | * either dependent on network access e.g. XMLHttpRequest or, 338 | * other parts not inherently available in fenced frames e.g. Payment feature is dependent on the existence of opener/openee relationship 339 | 340 | Given the above, we would do an audit to see which features are safe to allow in this variant. In the initial launch though, we will likely go with a minimal list of features that we know are necessary for the personalized payment button to work, e.g. shared storage and Aggregate Reporting APIs. 341 | 342 | 343 | ### Process Isolation 344 | 345 | Fenced frames, like Shared Storage worklets, follow Chrome's [Site Isolation](https://www.chromium.org/Home/chromium-security/site-isolation/) model. As Site Isolation improves, so will the security provided to fenced frames. 346 | 347 | ### CSP:frame-ancestors 348 | CSP:frame-ancestors response header only checks up to the fenced frame root in information flows where the embedder’s origin cannot be known inside the fenced frame (e.g., Protected Audience fenced frames). For the information flow in this proposal, since the embedder’s information could be available inside the FF via the src url, it is not a privacy concern to let the CSP:frame-ancestors response header be checked all the way up to the outermost main frame. 349 | With this behavior, the fenced frame can then allowlist origins via CSP:frame-ancestors header that it is ok to be embedded in and exclude others. 350 | 351 | ## Stakeholder Feedback / Opposition 352 | 353 | This change impacts payment providers. We have heard from multiple payment providers about the need for personalized payment buttons, including Google Pay and Shopify. Here’s a [comment on the TAG review](https://github.com/w3ctag/design-reviews/issues/735#issuecomment-1206075921) showing support from Shopify: 354 | 355 | _“As signal boost. Want to note strong interest and support for this on behalf of Shopify. Same/similar [use case and reasons as outlined here](https://developers.googleblog.com/2021/05/updated-google-pay-button-increases-click-through-rates.html).”_ 356 | 357 | We have also [heard from TAG reviewers](https://github.com/w3ctag/design-reviews/issues/838#issuecomment-1662399487) about fenced frames’ capability to support non-ads use cases, as given below, and this solution will enable such use cases: 358 | 359 | _“We had a long discussion about how the shape of this, changing the relationship between an iFrame and its embedding page — it must not be unique to the advertising use cases you've listed._ 360 | 361 | _We brainstormed along the lines of a site presenting user-generated content in an iFrame, and the payments processes. Have you explored use cases outside the ones you're citing? And if so, what overlaps are you finding?”_ 362 | 363 | ## Alternatives considered 364 | 365 | **Alternatives considered: Cookies** 366 | 367 | As 3p cookies are planned to be [phased away](https://privacysandbox.com/open-web/) in Chrome (and in other browsers), there are new APIs that allow 3p cookie access under certain circumstances, e.g. the [requestStorageAccess API](https://groups.google.com/a/chromium.org/g/blink-dev/c/JHf7CWXDZUc). 368 | 369 | If cookies were used for this use case, the proposal will be similar to a variant of requestStorageAccess API being invoked and successfully resolved for an FF only if the FF has its network access disabled. 370 | 371 | **Benefits** 372 | 373 | The benefits of using cookies for this solution are the following: 374 | 375 | * Cookies are well known by developers and well supported by browsers. 376 | 377 | **Downsides** 378 | 379 | * If this solution applies to any 1p cookie then it will have the side effect of the user’s personalized data being sent on the network for every request. To avoid that, there will need to be a new attribute introduced, say “fenced”, so that they are not sent on the network and are only accessible inside a fenced frame. As opposed to the shared storage approach being primarily an API enhancement, this will also require enhancement to the cookies, by adding the “fenced” attribute. The getter code and spec will then need to handle the attribute separately such that it isn’t accessible inside an iframe. Also, the setter should not be accessible inside the FF. 380 | * The cookies being a default network concept does not align well with this change where the “fenced” cookies have to be JS-only. 381 | * Fenced frames by default have a unique and ephemeral partition for cookies and with this change, a given cookie’s value before and after the API resolving will be different, which might lead to confusion. Alternatively, cookie access in the FF before the transition can be blocked. 382 | 383 | **Alternatives considered: Local Storage** 384 | 385 | [Local Storage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage), like shared storage, is origin scoped and JS-only. Local storage is not an ideal choice for this use case, due to the following reasons: 386 | 387 | * Local storage, like other storage APIs, is being [partitioned](https://privacycg.github.io/storage-partitioning/) in iframes. To allow unpartitioned access, it will rely on a variant of [rSA for storage](https://groups.google.com/a/chromium.org/g/blink-dev/c/SEL7N-xIE5s). 388 | * Fenced frames, by default have a unique and ephemeral partition and either we would disable that access in read-only FFs or there would be a transition where the value of a given data could be different before and after the access is granted, leading to confusion. 389 | 390 | ## References 391 | [TPAC presentation from Sep 2023](https://docs.google.com/presentation/d/1TqtFtK4x3TMd96JEvkbApUaYVdIaUz9uz3wNGPTuqdU/edit?usp=sharing) 392 | 393 | [TPAC presentation from Sep 2024](https://docs.google.com/presentation/d/1xKwCrhN2pD_lxuPfurgjEDkfyAcf3wgxPS9njlG9tT0/edit?usp=sharing) 394 | 395 | [Related Issue](https://github.com/WICG/fenced-frame/issues/15) 396 | -------------------------------------------------------------------------------- /explainer/generic_payment_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WICG/fenced-frame/0fd535135e33ec42dc2cdb1b5fd4e0923d3da565/explainer/generic_payment_button.png -------------------------------------------------------------------------------- /explainer/integration_with_web_platform.md: -------------------------------------------------------------------------------- 1 | # Integration with the web platform 2 | This document goes into the various ways in which fenced frame interacts with the platform. The web platform is massive and so we expect this document to be a running document with ongoing additions. 3 | 4 | ## Source url 5 | The initial source url for the fenced frame is subjected to various restrictons or no restrictions depending on the use case for the fenced frame. Refer to the use cases document [here](https://github.com/WICG/fenced-frame/blob/master/explainer/use_cases.md) that discusses the source url for each of those. 6 | 7 | ## Origin 8 | The origin of the fenced frame will be the regular origin that it got navigated to. For opaque src, the origin will be that of the url was mapped to by the browser. Any origin-keyed storage and communication channels with other same-origin frames outside the fenced frame tree will be disallowed by using a partitioning key with a nonce. The storage key will use the same nonce for the nested iframes and the root fenced frame, so that same-origin channels can still work within the fenced frame tree. Essentially, along with the storage partitioning effort, the storage and broadcast channel access will be keyed on for the root frame and for a nested iframe. More details related to this can be found [here](https://github.com/WICG/fenced-frame/blob/master/explainer/storage_cookies_network_state.md). 9 | 10 | ## Size 11 | The API that generates a fenced frame config can pick the initial size that the fenced frame document sees, subject to whatever restrictions it deems necessary for its privacy model. If the initial size is fixed, then any changes the embedder makes to the width and height attributes of the will not be reflected inside the fenced frame. 12 | 13 | ## Viewability 14 | Viewability events using APIs like [Intersection Observer](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) can be a communication channel from the embedding context to the fenced frame. However, to be used as a covert channel, it does require movement of the frame containing the ad on the screen and therefore is hostile to user experience. 15 | Viewability events are important information in the ads workflow for conversion reports and billing; therefore, Intersection Observer will be fully supported in fenced frames and it will be phased out only if/when an alternative mechanism is launched. In the meantime, we plan to add metrics to understand honest use and detect abuse, to help guide the need/development of these eventual mechanisms or mitigations. 16 | 17 | ## Visibility 18 | APIs like [visibilityState](https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilityState) and the corresponding [visibilityChange event](https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilitychange_event) determine the visibility of the tab based on user actions like backgrounding etc. A fenced frame and the main page could join server-side on the basis of when they lose and gain visibility. This kind of joining is also possible with other joining ids like the fenced frame creation time. The network side channel and future mitigations are described more [here](https://github.com/WICG/fenced-frame/blob/master/explainer/network_side_channel.md). 19 | 20 | ## Accessibility 21 | For accessibility, fenced frames will behave like iframes, they will be part of the accessibility tree and a11y users can navigate through its contents with a screen reader. 22 | “title” is an attribute read by screen readers for an iframe and that will continue to be used for fenced frames. A script inside a fenced frame cannot access the title attribute via the same-origin channel window.frameElement.title since frameElement is null for fenced frames. 23 | 24 | ## Interactivity 25 | Fenced frames would have normal user-interactivity as an iframe would. 26 | 27 | ## Focus 28 | Since fenced frames require interactivity, they would need to get system focus. It could be a privacy concern in the following ways: 29 | * A fenced frame and the main page could join server-side on the basis of when one lost focus and another gained focus. The network side channel and future mitigations are described more [here](https://github.com/WICG/fenced-frame/blob/master/explainer/network_side_channel.md) 30 | * For programmatic focus, calling element.focus() might invoke blur() on an element that is in the embedding page thus making a channel from the fenced frame to the embedding page. So the mitigations there would be: 31 | * Only allow programmatic focus()/blur() to be successful if the fenced frame already has system focus. 32 | * Only allow system focus to move to a FF on a user gesture including hitting the tab key and not because of calling focus(). 33 | 34 | ## PostMessage 35 | A fenced frame does not allow communication via PostMessage between the embedding and embedded contexts. A fenced frame will be in a separate browsing context group then its embedding page. 36 | 37 | ## Session History 38 | Fenced frames can navigate but their history is not part of the browser back/forward list as that could be a communication channel from the fenced frame to the embedding page. Additionally, fenced frames will always have a replacement-only navigation (back/forward list of length 1) which is a simpler model since it doesn't imply that there's a hidden list of back/forward entries for the nested page, only accessible via history APIs and not via the back/forward buttons, etc. This is also consistent with the iframes new opt-in mode for disjoint session history as discussed in https://github.com/whatwg/html/issues/6501. 39 | 40 | ## Content Security Policy 41 | Fenced frames ineractions with CSP are detailed [here](https://github.com/WICG/fenced-frame/blob/master/explainer/interaction_with_content_security_policy.md). 42 | 43 | ## Permissions and policies 44 | This is discussed in more detail [here](https://github.com/WICG/fenced-frame/blob/master/explainer/permission_document_policies.md). 45 | 46 | ## COOP and COEP 47 | Although COOP is only defined for top-level documents, it has impacts on popups opened by subframes in the page. Because COOP is crucial to the web exposed mitigation against Spectre, Fenced Frames must support COOP in one way or another. Because COOP contains a reporting endpoint, we cannot actually pass the COOP value to the Fenced Frame. So to support COOP, we have two options: 48 | * Forbid Fenced Frames from opening popups entirely. 49 | * Mandate that popups opened from Fenced Frames always have rel no-opener and place them in another BCG (ie the behavior of the strictest form of COOP). We propose fenced frames to take this approach as opening popups is an important functionality that needs to be supported e.g. when a user clicks on an ad in a fenced frame. 50 | 51 | For COEP, If the fenced frame’s embedding page enables COEP then the fenced frame document should allow itself to be embedded as described [here](https://docs.google.com/document/d/1zDlfvfTJ_9e8Jdc8ehuV4zMEu9ySMCiTGMS9y0GU92k/edit#bookmark=id.kaco6v4zwnx2). COEP provides two bits of information to a fenced frame: whether the embedder has COEP enabled, and whether the fenced frame is same-origin with its embedder (through the additional CORP check). We could remove the second one by having COEP always be checked regardless of whether the document in the fenced frame is same origin with its embedder or not. In the initial origin trial, fenced frames behavior will match that of iframes and eventually we will make fenced frames always behave as if it was cross-origin to the embedder. 52 | 53 | ## Opt-in header 54 | Since fenced frames allow a document to have many constraints in place, an opt-in mechanism is a good way for the document to accept those restrictions. The opt-in will make use of the Supports-Loading-Mode proposed [here](https://github.com/WICG/nav-speculation/blob/main/opt-in.md). 55 | 56 | It is also important for sites to opt-in due to security reasons, e.g. csp:frame-ancestors behavior. Frame ancestors checks will stop at the Fenced Frame root for Protected Audience fenced frames. All other fenced frames (e.g., for selectURL or created via FencedFrameConfig) will check all the way up to the primary top-level frame. Protected Audience is different because it is only allowed to have k-anonymous information flow into the fenced frame, and the primary top-level frame’s origin may not be k-anonymous. 57 | 58 | ## Fetch metadata integration 59 | To let a server know that a document is being requested for rendering in a fenced frame, a new Sec-Fetch-Dest HTTP Request Header value of `fencedframe` will be sent in the request. 60 | 61 | ## Unload and beforeunload handlers 62 | Fenced frames will not be supporting unload or before unload handlers. This is because of the following reasons: 63 | * Both of these have the existing issue of unreliability, so hopefully not supporting them should not lead to breaking critical workflows that depend on them. 64 | * There have been issues with both the handlers because running code when the user is trying to navigate away is not very respectful of the user. 65 | * It's a communication channel (the page deletion timestamp). It's not a major one since it's similar to the creation timestamp which is already present but disabling them will eliminate one communication channel between the embedding page and the fenced frame. 66 | 67 | ## Top-level navigation 68 | Some modes of fenced frames allow navigating the top-level frame. The approach adds a new target name called `_unfencedTop` (in the same category as `_self`, `_parent`, `_top`) that works with existing HTML elements/JS APIs (``, ``, `
`, `window.open`). Example usage: 69 | 70 | ``` 71 | // Navigates the top-level frame to 'url'. Subject to the same restrictions as sandboxed 72 | // iframes where top-level navigation is allowed upon user activation. 73 | window.open('url', '_unfencedTop'); 74 | 75 | 76 | Click me! 77 | ``` 78 | 79 | A few more details: 80 | * The user activation is checked only in the frame initiating the navigation and not in an ancestor outside the frame tree because user activation inside the fenced frame tree is not propagated outside the tree. 81 | * The url is subject to the same restrictions as other content-initiated top-level navigations, e.g. data urls are not allowed. 82 | * The opener/openee relationship would not be present for this navigation, which means the window.open example above will always return null. 83 | * Referer would be the frame that initiated the navigation which could be the fenced frame root frame or a nested iframe in the fenced frame tree (similar to a popup navigation). 84 | 85 | For more details, the implementation design doc can be found [here](https://docs.google.com/document/d/1vuwG31hCwZROIR1NaYjTrthmDrlXza0mZui7zzF93TM/edit?usp=sharing). 86 | 87 | For privacy implications of this API and others, see [the privacy considerations](https://github.com/WICG/fenced-frame/blob/master/explainer/README.md#privacy-considerations) section. 88 | 89 | ## Screen interface 90 | The [Screen interface](https://drafts.csswg.org/cssom-view/#the-screen-interface) provides information about the screen of the browser's output device, and as a result that information is visible to both fenced frames and the embedder. Currently there are no plans to fence the Screen interface, meaning that its attributes will retain the same values in both the fenced frames and their embedders. Justification for this decision can be found [here](https://docs.google.com/document/d/1sZOgnAUsIzNHOs_VVWF92er1jXmNCcv6k3vvOvixeFc/edit?usp=sharing). 91 | 92 | ## MediaDevices interface 93 | The [MediaDevices interface](https://w3c.github.io/mediacapture-main/#mediadevices) is able to list connected media devices via the [`enumerateDevices()`](https://w3c.github.io/mediacapture-main/#dom-mediadevices-enumeratedevices) method. The `deviceID` field in this method's output can potentially create consistent identifiers between same-origin frames embedded in different first-party sites. The [specification for `deviceID`](https://w3c.github.io/mediacapture-main/#dom-mediadeviceinfo-deviceid) states: 94 | 95 | "To ensure stored identifiers are recognized, the identifier MUST be the same in Documents of the same origin in top-level traversables. In child navigables, the decision of whether or not the identifier is the same across documents, MUST follow the User Agent's partitioning rules for storage (such as localStorage), if any, to not interfere with mitigations for cross-site correlation." 96 | 97 | Fenced frames partition storage using a unique nonce, so that no other frame can access the same partitioned storage as a given fenced frame. As a result, deviceID values will always be different within two fenced frames and similarly the value in a fenced frame will always differ with that in other iframes/top-level frames, even if their origin is the same. 98 | 99 | ## WebRTC 100 | [WebRTC](https://webrtc.org/) ([spec](https://www.w3.org/TR/webrtc/#intro)) is an open standard and set of APIs with two primary purposes: 101 | 102 | 1. Enable media capture of cameras, microphones, and displays. 103 | 1. Facilitate peer-to-peer communication between clients for the purpose of sharing captured media or other arbitrary data. 104 | 105 | WebRTC enables critical use cases of the web today, like audio and video chat, and we need to ensure that fenced frames account for its usage. And in a way, they already do. Capture of cameras, microphones, and displays are gated behind permissions policies, and in fenced frames, **those policy-gated features are [unconditionally disallowed](https://github.com/WICG/fenced-frame/blob/master/explainer/permissions_policy_for_API_backed_fenced_frames.md#introduction).** This means that many primary use cases enabled by WebRTC are not supported, and there are no plans to support them unless necessary use cases are identified. 106 | 107 | However, WebRTC peer connections via `RTCPeerConnection` and `RTCDataChannel` are still enabled. This means that for fenced frames in the [local unpartitioned data access mode](https://github.com/WICG/fenced-frame/blob/46c479e01d741dfab8429bc18e5f3193e4fd6db0/explainer/fenced_frames_with_local_unpartitioned_data_access.md#revoking-network-access), we would have to spec and build behavior to disable WebRTC peer connections after calling `window.fence.disableUntrustedNetwork()`. We’ve decided against doing so, and will instead **disable `RTCPeerConnection` construction in all fenced frames, regardless of whether network access has been voluntarily disabled or not**. We have a few reasons for making this choice: 108 | 109 | 1. Utility: We have not yet identified any use cases for fenced frames that would require WebRTC peer connections. 110 | 1. A significant amount of WebRTC utility is already hampered by the disabled media capture permissions. 111 | 1. Privacy: Network communications of any kind present a [privacy side-channel](https://github.com/WICG/fenced-frame/blob/46c479e01d741dfab8429bc18e5f3193e4fd6db0/explainer/network_side_channel.md#network-side-channel), and we should take the opportunity to close these channels where we can. 112 | 1. Complexity: Network revocation for `RTCPeerConnection` would likely be more involved than other types of requests, for potentially little benefit given 1 and 2. 113 | 114 | Navigation, subresource fetches, and Websockets will still be enabled in fenced frames by default, but disabled after a call to `window.fence.disableUntrustedNetwork()`. 115 | 116 | ## Chromium implementation: Top-level browsing context using MPArch 117 | Chromium is implementing [Multiple Page Architecture](https://docs.google.com/document/d/1NginQ8k0w3znuwTiJ5qjYmBKgZDekvEPC22q0I4swxQ/edit?usp=sharing) for various use-cases including [back/forward-cache](https://web.dev/bfcache/), [portals](https://wicg.github.io/portals/), prerendering etc. This architecture aligns with fenced frames requirement to be a top-level browsing context as MPArch enables one WebContents to host multiple pages. Additionally, those pages could be nested, as is the requirement for fenced frames. 118 | 119 | A page in MPArch behaves as the top-level frame for their frame tree and as a top-level browsing context from a spec perspective. Any calls to window.parent, window.top or window.frames[x] work for the inner and outer pages independently i.e. a frame in the inner page cannot access the outer page using window.parent/top etc. A fenced frame does not allow script access to the embedding context and thus aligns well with being implemented using MPArch. The implementation design is detailed here: 120 | [fenced frames implementation design](https://docs.google.com/document/d/1HAU9IiHZU4KBPC_rEk3BQYrWTK50PdNGg8CcHhVLXig/edit?usp=sharing) 121 | 122 | ### How new features should integrate with fenced frames 123 | 124 | When implementing a new feature on the web platform, its integration with many other parts of the web platform must be considered, e.g., [inactive Documents in the BFCache](https://w3ctag.github.io/design-principles/#support-non-fully-active), and [prerendering](https://wicg.github.io/nav-speculation/prerendering.html#delay-async-apis). Fenced frames adds another dimension within which new features must consider their behavior. We've written some preliminary guidelines on how to think about the behavior of new features that operate within a fenced frame [**here**](https://chromium.googlesource.com/chromium/src/+/master/content/browser/fenced_frame/README.md), which we will consider upstreaming to a more broad venue, perhaps like the [W3C TAG Design Principles](https://w3ctag.github.io/design-principles/) document. 125 | 126 | ### Obsolete: Initial version: using shadowDOM based iframes 127 | While MPArch is being developed in parallel with fenced frames, the initial implementation that will be available for origin trial will be based on the shadowDOM architecture. The implementation design is detailed here: 128 | [Fenced Frames Origin Trial Design: ShadowDOM + IDL](https://docs.google.com/document/d/1ijTZJT3DHQ1ljp4QQe4E4XCCRaYAxmInNzN1SzeJM8s/edit?usp=sharing) 129 | 130 | ## Browser features 131 | There are many chrome browser features e.g. autofill, translate etc., that will need to be considered on a case-by-case basis as to how they would interact with a fenced frame with possible approaches being: 132 | * Treat the feature as if it would behave in a cross-origin iframe. 133 | * Treat the feature as if fenced frame was a separate top-level page. 134 | * Do not support the feature at all. 135 | 136 | ### Extensions 137 | It is important for fenced frames to be visible to extensions especially content blockers since many of them block advertisements. 138 | In terms of non-content blocker extensions, they should also be able to interact with fenced frames as they would with another page. Note that malicious extensions might be able to override the privacy protections here by creating cross-site identifiers but that threat is larger than just fenced frames and would need to be handled as a separate effort. 139 | 140 | ### Developer tools 141 | Fenced frames should have developer tools access as an iframe would. 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /explainer/interaction_with_content_security_policy.md: -------------------------------------------------------------------------------- 1 | # **Fenced Frames interaction with Content Security Policy** 2 | 3 | 4 | ## **Why are fenced frames different than iframes when it comes to CSP** 5 | 6 | Content Security Policy is a defense against cross-site scripting attacks, allowing developers to harden their own sites against injection of malicious script, style, and other resource types. [CSPEE](https://w3c.github.io/webappsec-cspee/#csp-attribute) further extends it to embedded frames and relies on an explicit opt-in from the embedded content, which ought to make it possible for nested frames to cooperate with their embedders to negotiate a reasonable set of restrictions. 7 | 8 | Fenced frames behave differently than other embedded frames because no embedding site information should flow from the embedder to inside the fenced frame and CSPEE allows arbitrary data flow from the embedder to the fenced frame, as CSP's syntax is very flexible. That data is enough to be a channel for the embedding site to pass its url or user’s identity via those bits. 9 | 10 | The embedding site therefore should treat fenced frames differently and assume that the presence of a fenced frame on the site implies no control on the subresources of that frame via the csp attribute. 11 | 12 | ## Creating a fenced frame within an iframe 13 | 14 | Let's say a top-level site has 2 iframes, iframe1 and iframe2. The top-level site has applied the ‘csp’ attribute to iframe1 but not to iframe2. Iframe1 has accepted the policy via the request-response headers exchange. Note that `iframe1` by default cannot create a fenced frame since it is trusted by the top-level page that it will honor policy1 but if it creates a fenced frame that bypasses the policy, it can be used as a workaround to the restrictions posed by policy1. iframe2 however is allowed to create a fenced frame. 15 | 16 | **Future work:** An option here is to introduce a permission/csp directive that allows iframe1 to create a fenced frame bypassing its csp rules. If it’s a csp directive its absence should be considered `none` but that’s contradictory to how csp directives work. It could be an `allow` attribute instead. **TODO:** Preference if it should be a csp directive or a permission? 17 | 18 | 19 | ## **Existing CSP directives** 20 | 21 | The embedding site can restrict the fenced frame’s document to specific origins, using the frame-src/child-src/default-src directives. 22 | 23 | For example, let's say the top-level site has the following policy: 24 | 25 | `Content-Security-Policy: frame-src: *.b.test` 26 | 27 | An a.test fenced frame cannot be created since it is not allowed via the embedding frame’s csp. A b.test fencedframe can be created. 28 | Note than based on the discussion in the above section, an a.test fenced frame can be created from within iframe2. 29 | 30 | Note that this is not applicable to opaque urls which are discussed in the next section. 31 | 32 | 33 | # **Opaque URL** 34 | 35 | The first use cases for fenced frames are going to be for [opaque ads](https://github.com/WICG/fenced-frame/blob/master/explainer/use_cases.md#opaque-ads) and since the url of the fenced frame needs to be hidden from the embedding page, we cannot apply the frame-src directive directly to the mapped url, since CSP reporting can reveal to the embedding page if a fenced frame was successfully created or not. This would lead to the embedding page deriving the possible origins of the opaque ad, going against the isolation guarantees of this mode. 36 | 37 | The other option of requiring the embedding site to mention urn:uuid (scheme of the opaque url) in their CSP rules to allow opaque ads, is also not feasible. The limitation is that there are a large number of publisher sites that currently have their csp set to e.g. `frame-src: https:` and requiring the publisher sites to change their headers in order to allow interest-group based advertising to work correctly, is not amenable to deployment. 38 | 39 | 40 | ## Proposal - Scheme source matching 41 | 42 | Note that irrespective of a CSP policy, fenced frames are restricted to be created only in [secure contexts](https://w3c.github.io/webappsec-secure-contexts/) and only from [potentially trustworthy urls](https://w3c.github.io/webappsec-secure-contexts/#potentially-trustworthy-url). Given these restrictions, we could apply the csp scheme-source directives to the scheme of the mapped url without a privacy leak concern. Here are some examples for this approach: 43 | 44 | 45 | 46 | * If the policy is as given below, then allow an opaque ad that maps to an https url 47 | 48 | ``` 49 | Content-security-policy: frame-src https: http://example.com 50 | ``` 51 | 52 | Or 53 | 54 | 55 | ``` 56 | Content-security-policy: frame-src https://*:* http://example.com 57 | ``` 58 | 59 | Or 60 | 61 | 62 | ``` 63 | Content-security-policy: frame-src * http://example.com 64 | ``` 65 | 66 | 67 | * If the policy is as given below, then do not allow any opaque urls to be loaded since the site has given permission to only specific hosts or no hosts, respectively. 68 | 69 | ``` 70 | Content-security-policy: frame-src http://example.com 71 | ``` 72 | 73 | Or 74 | 75 | ``` 76 | Content-security-policy: frame-src` ‘`none`‘ 77 | ``` 78 | 79 | 80 | ### Advantages of this approach: 81 | 82 | 83 | 84 | * Allows backward compatibility with existing sites. 85 | * Respects the csp rules for host-sources 86 | 87 | ### Future enhancements 88 | 89 | 90 | 91 | * Only https or more potentially trustworthy schemes: If opaque fenced frames can map to non-https potentially-trustworthy urls and if we do allow https scheme-source to only match https urls but reject for others, this might be a privacy leak. For example, if the opaque fenced frame is created using [Shared Storage’s runURLSelectionOperation](https://github.com/pythagoraskitty/shared-storage#simple-example-consistent-ab-experiments-across-sites), then the 2 parties could collude to create 32 fenced frames and each of those would either be blocked or loaded to transmit one bit. 92 | 93 | * Support for https:\* to be treated as https: We only do this carve out to the spec and implementation if needed and reported as an issue. We don’t currently have this carve-out because it expects the default port and so acceptance/rejection of an opaque url based on this can leak some information. 94 | 95 | 96 | # **New CSP directive** 97 | 98 | A new CSP directive called fenced-frame-src to be introduced which if not present will fallback to frame-src/child-src/default-src. This new directive will benefit scenarios like the following: 99 | 100 | 101 | 102 | * If an embedding site doesn’t want to allow any opaque ads but still wants to allow other iframes, they can use a policy like: 103 | 104 | ``` 105 | Content-security-policy: fenced-frame-src 'none' ; frame-src https 106 | ``` 107 | 108 | 109 | * If an embedding site wants to allow any opaque ads but only allow iframes with specific host, they can use a policy like: 110 | 111 | ``` 112 | Content-security-policy: fenced-frame-src https: frame-src http://example.com 113 | ``` 114 | 115 | 116 | * If an embedding site wants to allow any non-opaque fenced frames e.g. for payment handling scenarios, but no iframes, they can use a policy like: 117 | 118 | ``` 119 | Content-security-policy: fenced-frame-src http://example.com ; frame-src `none` 120 | ``` 121 | 122 | # **Alternatives considered for opaque url fenced frames** 123 | * Apply policy to the mapped URL 124 | The alternative approach could have been to apply the csp header to the actual URL and not report it. That would be hard to roll out from a site owner’s perspective. The standard way to add or change a CSP on a site is: 125 | 1. Come up with a CSP the developer thinks is right 126 | 2. Turn it on with Content-Security-Policy-Report-Only and a reporting url 127 | 3. Verify the site is not getting any unexpected reports 128 | 4. Turn it on with Content-Security-Policy 129 | 130 | As long as the site is relatively unchanged during this process, if something's going to break in step 4 site owners will learn about it in step 3. If we go with this alternate approach, it would change this property: if the site or a third party library on the site puts fenced-frames on the page, it could break in step 4 without any notice. This breakage won't appear in CSP reporting, CSP violation events, or any page metrics. This would make CSP much riskier to deploy. 131 | * Specifically mention urn:uuid scheme 132 | In this approach, the embedding context says whether urn:uuid based fenced frames are allowed or not : `Content-Security-Policy: fenced-frame-src 'urn:uuid:*' `. Note that the embedding context does not have any say in whether the actual URL it maps to, should be allowed or not. The downside of this approach is that there is no backward compatibility. 133 | 134 | -------------------------------------------------------------------------------- /explainer/network_side_channel.md: -------------------------------------------------------------------------------- 1 | # Network side channel 2 | 3 | The privacy challenge is that the documents inside and outside the fenced frame can collude with a server to join an identifier across the fence boundary, using information like request timing and IP addresses. 4 | 5 | **Prerequisites of this attack** 6 | 7 | This side channel relies on the following factors being true: 8 | * There are colluding servers that are joining logs to be able to create cross-site user profiles. 9 | * There is common information available in the fenced frame context and the outer context. This is trivially available information like: 10 | * creation time of the fenced frame/ network request time, 11 | * IP address of the client. 12 | * With protected audience API (and other opaque URL fenced frames), there is also the privacy leak that a given URL was selected. Even with k-anonymity, each render url leaks a few bits and multiple auctions on the page can then be correlated to the identity of the user. 13 | 14 | **Example** 15 | 16 | As an example of Protected Audience API, the interest group of the user can be joined with the user’s identity on the publisher site. Once this attack is executed, a publisher can know that a given user on their site has been interested in "running shoes" and has been browsing sites related to "running shoes". 17 | Similarly, the advertiser/ad-tech can know the site their ad was shown on along with the user-id of the user on those sites. 18 | 19 | Consider the following example information flow: 20 | 21 | * Embedding site A sends a message to a tracking site, say tracker.example saying it is about to create a fenced frame and that the user id on A is 123. 22 | * The fenced frame is created and has access to user specific information X (e.g. user’s interest group for Protected Audience via the render URL). When the fenced frame document’s resources are requested from site B, X is also sent along. B can also let tracker.example know. 23 | * The tracking site tracker.example can then correlate using the time/IP address bits of both requests. 24 | * A can then know X via tracker.com 25 | 26 | The above is an example of a scenario where user id on A and user’s information on B can be joined without the user even interacting with the fenced frame. 27 | 28 | ## Mitigations 29 | 30 | These issues are not unique to fenced frames and also exist in cross-site navigations today. Having said that, it is considered part of fenced frames' threat model since these are embedded frames (as opposed to separate tabs) and we are actively looking into mitigations for the same. The mitigations could depend on any future solutions to these for cross-site navigations but also have additional specific mitigations for fenced frames such as ad rendering in which all network-loaded resources come from a trusted CDN that does not keep logs of the resources it serves. The privacy model and browser trust mechanism for such a CDN would require further work. 31 | 32 | For completeness, there are current mitigations in FFs consumer APIs to reduce the impact of this side channel: 33 | - The [variant of FF](https://github.com/WICG/fenced-frame/blob/master/explainer/fenced_frames_with_local_unpartitioned_data_access.md) where unpartitioned data may be read requires the FF to give up its network access before accessing any unpartitioned data and this network side channel therefore doesn't apply to that. 34 | - The other consumer APIs: Protected Audience(PA) and selectURL are currently handling this by restricting the inflow of information in the FF e.g. PA limits that the ad URL rendered in the FF [has to be k-anonymous](https://github.com/WICG/turtledove/blob/main/FLEDGE.md#:~:text=The%20k%2Danonymity%20protection%20for%20the%20auction%20winning%20ad%20creative%20URL%20is%20still%20important%20as%20the%20URL%20potentially%20contains%20information%20from%20two%20sites%2C%20the%20joining%20and%20auction%20sites.) and selectURL restricts the number of input URLs to 8 and applies [budgets](https://github.com/WICG/shared-storage/blob/main/select-url.md#budgeting). 35 | 36 | -------------------------------------------------------------------------------- /explainer/opaque_ads_use_cases.md: -------------------------------------------------------------------------------- 1 | # Obsolete: This file's contents are obsolete. Instead please look at https://github.com/WICG/fenced-frame/blob/master/explainer/use_cases.md 2 | 3 | ## Use-cases/Key scenarios 4 | 5 | Following are the use cases for fenced frames loading [ads with opaque urls](https://github.com/WICG/fenced-frame/blob/master/explainer/use_cases.md#opaque-ads). 6 | 7 | ### Interest Group ads based on user activity (TURTLEDOVE) 8 | 9 | [TURTLEDOVE](https://github.com/michaelkleber/turtledove) allows for showing ads based on an advertiser-identified interest, in a privacy-preserving manner. 10 | 11 | The following privacy aspects are required for turtledove: 12 | 13 | 14 | * Advertisers can serve ads based on an interest, but cannot combine that interest with other information about the person — in particular, with who they are (user’s identity on the embedding site) or what page they are visiting. 15 | * Web sites the person visits, and the ad networks those sites use, cannot learn about their visitors' ad interests. 16 | 17 | These privacy requirements can be met using the fenced frame for rendering the winning ad. 18 | 19 | #### Design 20 | 21 | The fenced frame has access to the winning ad which represents user’s interest group information. This information is cross-site data and should not be exfiltrated to the embedding site. 22 | The high level design for turtledove consists of two restricted environments, worklets and fenced frames: 23 | 24 | 25 | 26 | * The first one, worklets, is responsible for doing the on-device auction and the output of that is the input to the fenced frame. This is a restricted javascript execution environment that does the on-device auction. This has the following characteristics: 27 | * It is invoked by JS running in the regular publisher page environment, and use of the turtledove API creates this environment to run various pieces of ad-tech-written code in. 28 | * It requires signals from the context that act as inputs to the on-device auction e.g. the publisher page’s topic. 29 | * Since it is getting information from the embedding page, we need to make sure it is not exfiltrating that information to a backend server, and thus it is not allowed network access. 30 | * Since the result of the turtledove API needs to be restricted from the embedding page, communication to the embedding page is not allowed. 31 | * The output of this environment is opaque and not available to query via javascript. This makes the interest group of the user invisible to the embedding page. It is then passed to construct the fenced frame which is used to render the ad represented by the actual url mapped to this opaque url. 32 | * For more details, refer the [FLEDGE explainer](https://github.com/WICG/turtledove/blob/main/FLEDGE.md#design-elements). 33 | * The second environment is the fenced frame that renders the ad from the above algorithm. 34 | * Note that if the contextual ad wins the auction, it need not be rendered in the fenced frame. This will leak one bit conveying whether an interest group based ad won the auction or not but the upside is that the contextual ads do not need to be changed to be rendered inside a fenced frame. 35 | 36 | 37 | ### Conversion Lift Measurement 38 | 39 | [Conversion Lift measurement](https://github.com/w3c/web-advertising/blob/master/support_for_advertising_use_cases.md#conversion-lift-measurement) studies are A/B experiments that ad providers perform to learn how many conversions were caused by their ad campaign vs how many happen organically. To be able to infer the causality of a conversion with the ad campaign, it requires deciding which experimental group the user should consistently be placed for a study (across sites) and show the ad creative corresponding to that group. (Related work: [Private lift measurement API by Facebook](https://github.com/w3c/web-advertising/blob/master/private-lift-measurement-third-party.md)). Shared Storage's [runURLSelectionOperation](https://github.com/pythagoraskitty/shared-storage#simple-example-consistent-ab-experiments-across-sites) can be used for achieving this and rendering the resulting url in a fenced frame using an opaque urn:uuid. 40 | 41 | The following privacy aspects are required for lift measurement: 42 | * The embedding site should not know which experiment group the user belongs to or which ad got rendered as a result of an A/B experimentation API. 43 | 44 | This is a privacy threat because if a publisher knows which experiment group a user is in for, say, n experiments, it gives the publisher an ‘n’ bits user identifier which can also be read on another site, forming a persistent cross-site identifier for the user. 45 | 46 | These privacy requirements can be met using the fenced frame for rendering the ad. 47 | 48 | 49 | #### Design 50 | 51 | A high level flow of the design using fenced frames is given below: 52 | 53 | 54 | 55 | * Outside of the fenced frame, the contextual ad auction returns two ad creative URLs, one for the control arm and one for the experiment arm. 56 | * Shared Storage's [runURLSelectionOperation](https://github.com/pythagoraskitty/shared-storage#simple-example-consistent-ab-experiments-across-sites) is then invoked which returns the ad as an opaque output based on user's experiment group. 57 | * The fenced frame is then created with the ad creative which mapped to the opaque output from the restricted JS environment. 58 | 59 | -------------------------------------------------------------------------------- /explainer/permission_document_policies.md: -------------------------------------------------------------------------------- 1 | # Fenced frames: permissions and document policies 2 | 3 | ## Introduction 4 | 5 | This document goes into how fenced frames interact with various ways of policy delegation available on the web platform, namely, [permission policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Feature_Policy) and [document policy](https://wicg.github.io/document-policy/ ). 6 | 7 | 8 | ## Permission Policy 9 | 10 | As mentioned in the list [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy#directives), some of the powerful features that permission policy (earlier known as feature policy) supports are autoplay, geolocation, camera etc. The HTTP header provides a mechanism to allow and deny the use of browser features in its own frame, and in content within any <iframe> elements in the document. The way a top-level page can currently deny/allow these features in an iframe does not work with fenced frames for the following reasons. 11 | 12 | * Some permissions-backed features (such as fullscreen and picture-in-picture) have actions that are observable from an embedder, which would create a data exfiltration channel if enabled in a fenced frame. 13 | * If permissions are delegated to a fenced frame, the fenced frame can then invoke a number of these APIs and based on whether each of them are allowed or not, it can be used to communicate a bitmap from the embedding page to the fenced frame. 14 | * It then prompts the question as to whether it is possible for the fenced frame to behave like a top-level browsing context and do its own header exchange to determine what needs to be allowed/denied in the fenced frame tree. If the actual top-level page had denied a feature for an origin e.g. Feature-Policy: geolocation 'none' and a fenced frame is allowed to use geolocation via its own header exchange, then it acts as a workaround for the restrictions placed on embedded frames and leads to an escalation of privilege attack. 15 | 16 | Different fenced frame configurations still need permissions-backed features to function properly. To handle that without compromising privacy, different behaviors are specified based on the existing privacy guarantees of the fenced frame: 17 | 18 | * Fenced frames that guarantee k-anonymity (i.e. fenced frames loaded with opaque URNs created through an API like Protected Audience) have a fixed list of permissions that must be delegated to it by the embedder in order for it to load. This forces the embedding context to have the same permissions bitmap as any other embedding context the fenced frame would be loaded in, removing that fingerprinting channel while also preventing privilege escalation. There is [a proposal to add permissions more flexibly rather than relying on a fixed list](https://github.com/WICG/fenced-frame/blob/master/explainer/permissions_policy_for_API_backed_fenced_frames.md), but this change is not currently planned on being implemented. 19 | * Fenced frames that do not guarantee k-anonymity (i.e. developer-created fenced frames loaded with a transparent URL) can inherit permissions from its embedder, since the fingerprinting vector is not a concern. Because the data exfiltration channel is still a concern, we only allow select permissions-backed features that do not have data exfiltration risks. 20 | 21 | See [this permissions policy file](https://source.chromium.org/chromium/chromium/src/+/main:services/network/public/cpp/permissions_policy/fenced_frame_permissions_policies.h) for a full list of the fixed permissions (for the k-anon case) or the list of permissions that can be enabled (for the non k-anon case). 22 | 23 | Permissions-backed features themselves can still introduce data leaks when enabled. [This document](https://source.chromium.org/chromium/chromium/src/+/main:content/browser/fenced_frame/PERMISSIONS_POLICIES.md) outlines that in greater depth, and includes an audit of which features are safe to enable for what kinds of fenced frames. 24 | 25 | ### Summary 26 | 27 | Given the above challenges, permissions delegation will either need to be disabled or requires a separate verification to ensure that it is not used to communicate user identifying information. Completely disabling doesn't work for our main use cases e.g. FLEDGE ads require usage of APIs like attribution reporting to be able to do reporting correctly. To see how those are planned to be supported, please read https://github.com/WICG/fenced-frame/blob/master/explainer/permissions_policy_for_API_backed_fenced_frames.md 28 | 29 | Relatedly, [Permissions API](https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API) should return the correct result inside a fenced frame tree. 30 | 31 | 32 | ### UA Client hints: open question 33 | 34 | 35 | 36 | * UA Client hints is one of the features that rely on [using permissions policy delegation](https://github.com/WICG/ua-client-hints#for-example) by the top-level page for allowing certain client hints to be used by an embedding frame. Since delegation won’t be allowed, should the fenced frames be allowed to behave like top-level contexts to figure out which client hints should be sent, via the Accept-CH headers but like iframes, not read/write from the origin’s client hints opt-in cache? That could lead to an escalation of privilege but may be better for utility. Client hints contain high-entropy and sensitive data but might be needed for normal functioning of a site. 37 | * Initially user agent client hints will be disallowed similar to all other permission policy based features. 38 | 39 | 40 | ## Document Policy 41 | 42 | Document policy allows the top-level page to configure features on a frame via the ‘policy’ attribute. The embedded frame’s document request will then go on the network with a `Sec-Required-Document-Policy` header and the frame will only load if the response comes back with the same or stricter document policy. Since this depends on delegation, it has the same issues as the permissions policy or CSPEE with respect to being used as a communication channel. Since this is applied per-document (vs per origin in permissions policy), it is closer to CSPEE. 43 | 44 | Similar to [CSPEE handling in fenced frames](https://github.com/WICG/fenced-frame/blob/master/explainer/permission_document_policies.md), the embedding site should treat fenced frames differently and assume that the presence of a fenced frame on the site implies no control on the policies of that frame via the policy attribute. 45 | 46 | The escalation of privileges attack mentioned above for permissions policy does not apply to document policy since this is delegated per-embedded frame and not per-origin and the embedding site can clearly distinguish between which frames can and cannot be controlled via delegation. 47 | 48 | Additionally, the fenced frame can still have document policy headers for itself and its embedded frames independent of the embedding tree. 49 | 50 | 51 | ### Summary 52 | 53 | Document policy cannot be delegated to a fenced frame, but it can be set as a top-level frame. 54 | 55 | 56 | ### Open Questions 57 | 58 | 59 | 60 | * One of the newer features to be added to the document policy is getViewportMedia as is being discussed in this [issue](https://github.com/w3c/mediacapture-screen-share/issues/155). This feature will only be able to work for a tab if all embedded frames opt-in via document policy. What should be the fenced frames behavior in such cases? 61 | * **Proposed:** A fenced frame is fine to be part of a screen capture if the frame is opted in and the user agrees to the permission as well. This is acceptable from a threat model perspective because screen capture of another tab is also possible today (gated on permission and user acceptance). 62 | * **Open question:** The above proposal implies that there will need to be a list of features that the fenced frame should know to opt-in and that is is hard to maintain as the list grows. This question is not yet resolved for the upcoming initial trial of fenced frames but since required document policy isn't yet launched, the lack of a solution is not currently breaking a workflow. 63 | -------------------------------------------------------------------------------- /explainer/permissions_policy_for_API_backed_fenced_frames.md: -------------------------------------------------------------------------------- 1 | 2 | # **Permission policy for API backed fenced frames** 3 | 4 | > **_NOTE:_** There are currently no plans to implement this feature at this time. 5 | 6 | # **Introduction** 7 | 8 | Current behavior in the origin trial is that all of the permission policy based features in fenced frames are disallowed (with a caveat given in Note below). This is to make sure that the permission delegation doesn’t act as a communication channel as well as there isn’t any escalation of privilege by virtue of creating a fenced frame. 9 | 10 | 11 | 12 | Lately, we have heard feedback for certain features to be enabled, specifically in [opaque-ads mode fenced frames](https://github.com/WICG/fenced-frame/blob/master/explainer/modes.md#opaque-ads) (or API-backed fenced frames). The feedback is for the following 2 features but we would like to have a solution that can extend to other features as well: 13 | 14 | 15 | 16 | 1. Attribution reporting: [github issue](https://github.com/WICG/fenced-frame/issues/37). 17 | 2. Shared storage APIs: [github issue](https://github.com/WICG/fenced-frame/issues/44). 18 | 19 | **Note:** As an incremental step to the proposed solution, the OT recently added an exception for attribution-reporting and shared-storage APIs. 20 | It allows a fenced frame to be navigated successfully only if the embedding frame has not opted out from these features and enables it for the fenced frame by default (without an allow attribute). 21 | 22 | 23 | # **Proposed Solution** 24 | 25 | The proposed solution is to extend the config-bound attributes as described in this [issue](https://github.com/WICG/fenced-frame/issues/48) to also include the permissions that the fenced frame’s consumer API considers important for a particular url to load. 26 | 27 | There are various inputs to compute the final permissions for a document loaded in the fenced frame. Dividing them further into what currently exists for iframes vs the new ones: 28 | 29 | Inputs that exist today in iframes: 30 | 31 | 32 | 33 | 1. **`allow-attribute`**: “Allow” attribute will have the same semantics as in an iframe and will enable the embedder to set permissions explicitly on a fenced frame similar to how it happens with iframes. 34 | 2. **`document-response-restricted-permissions`**: Optionally, the fenced frame document response headers can further restrict the permissions similar to how it happens in an iframe. 35 | 36 | Inputs that are new in the fenced frames workflow: 37 | 38 | 39 | 40 | 1. **`required-permissions-to-load`**: This is the set of permissions that the API declares as the permissions “required” for the fenced frame to be navigated to a given url. Any permissions outside this set will not be available in the fenced frame. This allows these permissions to be verified for k-anonymity and not have more permissions added that were not verified. 41 | 1. If a permission which is part of this set is not allowed by the embedding frame, then the FF will not navigate successfully. This is required for fenced frames because if it can be detected by the FF’s document that a permission is not allowed, then it can be used as a communication channel from the embedder to the FF. 42 | 2. This set of permissions may be derived by the FLEDGE/SharedStorage APIs in various ways: 43 | 1. A default list maintained by the browser. Having a default list for an API reduces developer effort. For example, each interest group author need not put “attribution reporting” as part of their FLEDGE interest group. 44 | 2. Additional inputs e.g. defined as an argument to the runAdAuction API. Let’s call that **`predeclared-allow-attribute`**. This allows the API to consider the permissions granted as inputs to the auction. 45 | 46 | The algorithm steps will be as follows: 47 | 48 | 49 | 50 | 1. The embedder calls an API (e.g. navigator.runAdAuction()) to generate a config. The API takes `predeclared-allow-attribute`, any default list as mentioned above into consideration and picks `required-permissions-to-load`. Any permissions that are allowed inside the fenced frame should have gone through the k-anonymity check along with the url and resulted in **`required-permissions-to-load` .** 51 | 2. The embedder loads the config in the FF. 52 | 1. If **`allow-attribute`** does not contain a permission that is part of **`required-permissions-to-load`**, then the FF fails to load. 53 | 2. Otherwise navigate the fenced frame and only allow the permissions in **`required-permissions-to-load`** to be delegated to it even if **`allow-attribute`** contained more permissions than that. 54 | 3. The fenced frame loads the document and the response headers **`document-response-restricted-permissions`** can further restrict the permissions applied to the document similar to how it does for an iframe. 55 | 56 | ### Which features/permissions can be granted to a fenced frame 57 | 58 | Some permission based features may not align well with the privacy guarantees of an API, e.g. we do not want to allow JoinAdInterestGroup from a FLEDGE FF since users would expect to join an IG from a top-level page they visited and not from an ad. Similarly, we might not allow a hypothetical feature for getting unpartitioned cookies in a FLEDGE fenced frame given that FLEDGE does not allow microtargeting. APIs can therefore additionally have allow-lists based on their privacy guarantees and that would further restrict the **`required-permissions-to-load`** in step 1 of the algorithm above. 59 | -------------------------------------------------------------------------------- /explainer/personalized_payment_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WICG/fenced-frame/0fd535135e33ec42dc2cdb1b5fd4e0923d3da565/explainer/personalized_payment_button.png -------------------------------------------------------------------------------- /explainer/process_isolation.md: -------------------------------------------------------------------------------- 1 | # Fenced frames process isolation 2 | 3 | ## Objective 4 | 5 | Fenced frames carry information that should not be shared with any other context. In order to ensure that fenced frames cannot communicate with external contexts, we need to isolate them at the process level as well as the API layer. This is due to the various side-channel leaks that can occur between same-process scripts (e.g., spectre). This document describes the process isolation behavior required for fenced frames. 6 | 7 | 8 | ## Notes and assumptions 9 | 10 | 11 | 12 | * Any special process isolation logic for fenced frames will not be part of the initial launch but will be added eventually. 13 | * Fenced frames are always in a separate browsing instance (browsing context group) in the eventual MPArch architecture (and not in the interim shadowDOM architecture, since fenced frames will be based off on iframes). 14 | * Being in the same process as another frame implies it is possible for either frame to look into the data held by the other (see [spectre](https://spectreattack.com/)). 15 | * Presence of arbitrary code execution in the renderer process of either the fenced frame or the embedding page can lead to information sharing between the 2 contexts and guarding against these attacks helps enforce the privacy guarantees of fenced frames, which is that the embedding context and fenced frames should not be able to look into each others’ data 16 | * The severity given in each of the sections below is roughly based on the [guidelines](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/security/severity-guidelines.md) here. 17 | 18 | 19 | ## Embedding frame 20 | 21 | Even in the presence of an attacker with arbitrary code execution in the renderer process, fenced frame’s privacy threat model of not having access to the embedding page’s info and vice-versa should still apply. To get this, we will need to make sure that fenced frames are in distinct processes than the embedding frame. 22 | 23 | **Severity:** **high** 24 | 25 | 26 | ### Current and expected process isolation in Chrome 27 | 28 | **Desktop:** Currently, different site frames are assigned to different processes and on reaching process limit, same-site frames may be consolidated in a single process. So it looks like cross-site frames will always be in separate processes. That would be extended to make sure that fenced frames follow the process isolation of cross-site frames as well, since fenced frames essentially are treated as cross-site to all other frames. 29 | 30 | **Android:** On Android current behavior will not treat fenced frames in any special way but for post-OT launch, the idea is for them to be treated as special frames that are isolated even on Android. Given the low severity of fenced frames being together in the same process (see below), we can create a single process for all fenced frames to keep the number of processes low. 31 | 32 | **Implementation design:** [SiteInfo](https://source.chromium.org/chromium/chromium/src/+/main:content/browser/site_info.h;l=43;bpv=1;bpt=1?q=SiteInfo&ss=chromium) will require to be updated to handle fenced frames, in Desktop, to make sure same-origin non-fenced frames are not put together with a fenced frame (see below) and on Android to make sure fenced frames are allocated a separate process than their embedding site/cross-origin frames/same-origin non-fenced frames. 33 | 34 | For low-end devices, where no process isolation is feasible, fenced frames will be in the same process as their embedding frame and other frames. 35 | 36 | 37 | 38 | 39 | ## Cross-site frames 40 | 41 | As with the embedding page, the same threat exists with any other cross-site frame as well, so fenced frames should be in a distinct process than those. 42 | 43 | **Severity:** **high** 44 | 45 | 46 | ## Same site top-level frames 47 | 48 | Same-site top-level frames will have access to cookies and unpartitioned storage access while fenced frames will not have that access. 49 | In the presence of an attack, this privacy constraint should still be achieved so it would need to be in a separate process than another same-origin top-level document. E.g. if the same-origin top-level frame carries out a Spectre attack against a fenced frame, it can join that frame's data with its own cookies and thus compromise the user's privacy 50 | 51 | **Implementation design:** Since fenced frames are always a new BrowsingInstance, site isolation will try to put them in a separate process unless the process limit is reached. So we will need special logic for fenced frames so that their process is not merged even on reaching the limit. 52 | 53 | **Severity:** **high** 54 | 55 | 56 | ## Same site iframes 57 | 58 | Same-site iframes (on the same page) are able to communicate with the embedding site and thus in the presence of an attack, this could be used as a workaround for the fenced frame to communicate with the embedding site. Therefore they should be in distinct processes. 59 | 60 | **Severity:** **high** 61 | 62 | 63 | 64 | 65 | ## Same site fenced frames on the same page 66 | 67 | Since these are same-site, both fenced frames have almost the same information except possibly different sizes and different src URLs. Since sizes are restricted in the values that can be allowed and URLs being same-site, this still seems acceptable for them to be in the same process, in the presence of an attack. 68 | 69 | **Severity: low** 70 | 71 | 72 | ## Same site fenced frames on a different page 73 | 74 | Since these are same-site, both fenced frames have almost the same information except possibly different sizes and different src URLs. Similar to the above case, this seems less information and thus acceptable for them to be in the same process, in the presence of an attack. 75 | 76 | **Severity: low** 77 | 78 | 79 | ## Cross-site fenced frames 80 | 81 | Cross-site fenced frames whether on the same page or on a different page will be similar to the same-site fenced frame cases with the addition of the cross-site rendering URL also being an information that they can share with each other in the presence of an attack. 82 | 83 | **Severity: medium** 84 | -------------------------------------------------------------------------------- /explainer/storage_cookies_network_state.md: -------------------------------------------------------------------------------- 1 | # Fenced frames and storage/cookies/network state 2 | 3 | 4 | ## Introduction 5 | 6 | This document goes into how fenced frames interact with the various states associated with a document/site/origin e.g. cookies, storage etc. as well as the state associated with the corresponding network requests e.g. cookies, http cache etc. 7 | 8 | ## Non goals for this document 9 | 10 | Note that this document does not go into how unpartitioned storage/cookie access for modes like "read-only" and "unpartitioned-storage" will be supported. 11 | 12 | 13 | ## Fenced frame is not a nested browsing context 14 | 15 | It is important to note for this discussion, that even though fenced frames are embedded in another document, they are treated as top-level browsing contexts as explained [here](https://github.com/WICG/fenced-frame/blob/master/explainer/README.md#fenced-frame-api). This implies that we need to consider it’s interaction with both unpartitioned state (for fenced frame tree root) and partitioned state (for iframes nested in a fenced frame tree). The rest of the sections will detail how both of these states will be unique inside a fenced frame tree. A fenced frame is an isolated browsing context, with a carefully limited flow of information in and out. While in some cases a fenced frame is allowed to make network requests, we need to ensure that this does not open up new communication paths between the fenced frame and any other browsing context. 16 | 17 | 18 | ## Storage 19 | 20 | A fenced frame tree (the fenced frame root and any nested iframes) cannot access the same storage as another frame (top-level or nested) even though they may have the same storage key (same origin and top-level site). Once [storage partitioning](https://github.com/wanderview/quota-storage-partitioning/blob/main/explainer.md) is the default, fenced frames and their nested iframes will end up with storage keys of <fenced-frame-root-site, fenced-frame-root-origin> and <fenced-frame-root-site, current-frame-origin>, respectively ([existing storage key spec](https://storage.spec.whatwg.org/#storage-keys)). This is because fenced frame root is considered a top-level browsing context. But these keys are not unique and will allow sharing state with other frames outside this tree. To achieve uniqueness, we would be using the [nonce-based storage key](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/public/common/storage_key/storage_key.h;l=33?q=StorageKey::CreateWithNonce&sq=&ss=chromium) where all frames inside a given fenced frame tree will have the same nonce. Note that the same storage key will also partition origin-based communication channels like broadcastChannel. This will allow all same-origin frames within the tree to communicate with each other while disallowing any state sharing/communication outside the tree. The storage keys would then be <fenced-frame-root-site, fenced-frame-root-origin, nonce-for-this-tree> and <fenced-frame-root-site, current-frame-origin, nonce-for-this-tree>, for the fenced frame root and a nested iframe, respectively. 21 | 22 | ### Not available in the first version 23 | Note that this is a dependency on the storage partitioning workstream to be fully implemented and it will not be available in the very first experiment of fenced frames but will eventually be available. So for the first version, storage/service workers/broadcast channel will be unpartitioned and that will go away once storage partitioning implementation is complete. We will update the timelines here as and when they are clear. 24 | Cookies, however will be partitioned from the first version itself. See cookies section [below](https://github.com/WICG/fenced-frame/edit/master/explainer/storage_cookies_network_state.md#cookies). 25 | 26 | 27 | ### Developer perspective 28 | 29 | From a developer perspective, the same document/scripts can be reused for both fenced frames or for regular frames. That’s because storage access APIs are still allowed and do not return an exception. The difference that developers would need to understand is that none of the storage would be shared by any frame outside the tree. 30 | 31 | 32 | ## Network Isolation 33 | 34 | The [network isolation project](https://docs.google.com/document/d/1V8sFDCEYTXZmwKa_qWUfTVNAuBcPsu6FC0PhqMD6KKQ/edit?usp=sharing) attempts to prevent all persistent and session network data the browser stores on behalf of and about websites from being used to correlate the activity of a user across top-level browsing contexts for different sites. The state partitioned using network isolation keys include the [http cache](https://github.com/shivanigithub/http-cache-partitioning), Socket Pools etc. Similar to storage partitioning described above, fenced frames cannot share network state with other frames, even those with the same network isolation key (same top-level and frame sites). To achieve uniqueness of the network partition for each fenced frame tree, we would be using the [nonce-based network isolation key](https://chromium-review.googlesource.com/c/chromium/src/+/3015842) ([NIK spec](https://fetch.spec.whatwg.org/#network-partition-keys)) where all frames inside a given fenced frame tree will have the same nonce. This will allow all same-origin frames within the tree to access the same network partition. That enables them to access the same cached entries, for instance. The network isolation keys would then be <fenced-frame-root-site, fenced-frame-root-site, nonce-for-this-tree> and <fenced-frame-root-site, current-frame-site, nonce-for-this-tree>, for the fenced frame root and a nested iframe, respectively. 35 | 36 | 37 | ### Developer perspective 38 | 39 | The partitions of network state are not really visible to the developer except for the http cache functionality. All same-site frames within a single fenced frame tree will access the same cache partition. Developers would need to understand that the cache partition would not be shared with any frame outside this fenced frame tree. 40 | 41 | 42 | ## Cookies 43 | 44 | Since fenced frames are treated as top-level browsing contexts, they would by default have access to the unpartitioned cookies for that site. But that would allow sharing state with another same-site top-level page which is not permissible, given that fenced frames do not, by default, get access to unpartitioned storage. Therefore, any access to unpartitioned cookies will be disallowed for fenced frames. 45 | 46 | In conjunction with the partitioned cookies effort ([CHIPS](https://github.com/WICG/CHIPS)), the cookies inside a fenced frame tree can access partitioned cookies, but they would use a nonce to be unique to a fenced frame tree (similar to storage partitioning). This approach has the advantage of treating cookies and storage consistently. 47 | 48 | 49 | ### Alternative design for cookies 50 | 51 | Alternatively, cookies can be blocked but that would require special logic for fenced frames. Using unique and transient cookie partition as given above would align well with existing cookies infrastructure. 52 | 53 | 54 | ### Developer perspective 55 | 56 | The same document can continue to work for a fenced frame as for a regular frame, except that the cookie API calls and network requests will set/get cookies which are set in a transient and unique partition. 57 | -------------------------------------------------------------------------------- /explainer/use_cases.md: -------------------------------------------------------------------------------- 1 | # Fenced Frame Use Cases 2 | 3 | 4 | ## Summary 5 | 6 | This document describes some initial targeted use cases of the ` `element on the Web. For each, we’ll answer the following questions: 7 | 8 | 9 | 10 | 1. What parties are involved in this particular use case? This may include end users, web developers, or other parties like advertisers or payments providers. 11 | 2. Why does this use case require fenced frames? 12 | 13 | 14 | ## Common factors across all use cases 15 | 16 | Regardless of the context in which they are used, the primary goal of fenced frames remains the same. Fenced frames are designed to allow websites to embed content from other sites, with their cross-site data, in a way that intends to block communication between the embedder and fenced frame so that the cross-site data is not joinable 17 | 18 | Fenced frames largely achieve this by isolating themselves from their embedding context. A fenced frame and its embedder cannot access one another via JS window references, script access, storage access, messaging APIs, powerful permissions-policy-gated features, etc. Network constraints to prevent backend joins are forthcoming. 19 | 20 | The other documents in this repository go into much greater detail about the actual isolation mechanisms. This document focuses on how this isolation can be combined with other features of the Privacy Sandbox to provide privacy-respecting alternatives to critical use cases. 21 | 22 | 23 | ## Rendering Ads via the Protected Audience API 24 | 25 | The Protected Audience API enables on-device ad auctions by the browser, to choose relevant ads from websites the user has previously visited, without having to know who the user is. 26 | 27 | The Protected Audience API provides a privacy-friendly replacement for previous technologies used in advertising, like third-party cookies, which the Web is moving towards deprecating. The full details of this API can be found in the [explainer](https://github.com/WICG/turtledove/blob/main/FLEDGE.md), but here’s a brief summary: 28 | 29 | 30 | 31 | 1. When a site wants to sell ad space, the browser performs an on-device ad auction via `const config = await navigator.runAdAuction(...)`. The bidders in the auction are represented by interest groups, which are stored in the browser at an earlier time on an advertiser site via `navigator.joinAdInterestGroup()`. 32 | 2. The content of the winning ad is rendered in a fenced frame on the seller’s site and shown to the user. The `config` returned after running the auction is a `FencedFrameConfig`, which is used to load the ad content into a fenced frame. Some parameters of the `config`, such as the source URL, are redacted before being provided to the embedder. This redaction prevents the embedder from learning any information that was produced based on cross-site data. See the [explainer](https://github.com/WICG/fenced-frame/blob/master/explainer/fenced_frame_config.md) page for` FencedFrameConfig` for full details on how these are used. 33 | 34 | 35 | Using fenced frames to render the ad creative provides some significant privacy benefit to the end user. 36 | 37 | 38 | 39 | 1. A user’s interest group memberships constitute cross-site data. The embedder can never learn about the user’s interests when loading the fenced frame, because the `FencedFrameConfig` it receives doesn't expose any relevant information to the web platform. In addition, the information passed to the fenced frame will be _[k-anonymous](https://github.com/WICG/turtledove/blob/main/FLEDGE_k_anonymity_server.md)._ 40 | 2. Once the config has been loaded into the fenced frame and the ad is rendered, the embedder and the ad content cannot directly communicate with one another via web platform APIs. And since they don’t have third-party cookies, the only remaining ways to join user identity are via channels that we intend to deprecate over time (such as event level reporting) and via network fingerprinting attacks (which we’re also working on addressing). 41 | 42 | **Note: Today, Protected Audience API auctions allow the winning ad to be rendered in either an iframe or a fenced frame. This is to facilitate a smooth transition to fenced frames. Starting no earlier than 2026, auctions will only allow ads to be rendered in fenced frames.** 43 | 44 | 45 | ## Selecting and rendering a URL based on cross-site data via SelectURL 46 | 47 | Aside from executing ad auctions, there are other legitimate use cases on the Web that may rely on cross-site data, such as consistent a/b testing of content across sites, or having consistent display preferences for a embedded widget across sites.. The SelectURL API was created as a flexible mechanism to address these needs. More details can be found in the [explainer](https://github.com/WICG/shared-storage). Here’s a brief summary, as it relates to fenced frames: 48 | 49 | 50 | 51 | 1. Data is written to Shared Storage via setter methods, such as `sharedStorage.set()` and `sharedStorage.append()`. Setter methods are available in traditional browsing contexts via `window.sharedStorage`, and add data that can be accessed cross-site. 52 | 2. Access to the data occurs in a restricted context called a worklet, which is not allowed to directly communicate Shared Storage data to the page. 53 | 3. Instead, the page calls `sharedStorage.selectURL()` to select one of up to 8 possible URLs to display to the user based on this cross-site data. This method accepts a list of URLs, and returns a redacted `FencedFrameConfig` that can be used to load one of the URLs within a fenced frame. 54 | 4. The chosen URL is determined in the worklet by accessing Shared Storage data via `sharedStorage.get()`. However, the browser redacts this URL when placing it into the `FencedFrameConfig`, which prevents the page calling `selectURL()` from determining how cross-site data influenced the outcome. For a code example in a real-world context, take a look at [this section](https://github.com/WICG/shared-storage#simple-example-consistent-ab-experiments-across-sites) of the Shared Storage explainer. 55 | 56 | This framework is generic enough that it can fill many niches, but some specific use cases that have been identified for advertising are: 57 | 58 | 59 | 60 | 1. A/B testing. Sites can test advertisements or other types of content by partitioning users into experiment groups via a seed placed into Shared Storage. 61 | 2. Respecting user display preferences for widgets across sites. 62 | 63 | Much like the Protected Audience API, `selectURL` allows sites to make decisions about what content to show users based on cross-site data, but takes steps to prevent exposure of that data using an isolated worklet, a fenced frame, and a redacted `FencedFrameConfig`. Cross-site data remains contained to the worklet, and the URL selected as a result of that data is unknown to the embedding page. 64 | 65 | **Note: Today, sharedStorage.selectURL() allows the chosen URL to be rendered in either an iframe or a fenced frame. This is to facilitate a smooth transition to fenced frames. Starting no earlier than 2026, the chosen URL will only be rendered in a fenced frame.** 66 | 67 | 68 | ## Personalizing Document Content with Local Unpartitioned Data Access 69 | 70 | **_[Not launched as of H1 2024]_** 71 | 72 | We would eventually like to constrain fenced frames in such a way that their network communications do not leak significant amounts of cross-site user data. Without arbitrary network access, we can allow the fenced frame access to user's cross-site data. This would allow for cross-site rendering customizability, which is needed for some use cases such as for third-party payment providers. This section describes a use case in which the fenced frame’s script voluntarily disables its network access, in order to access cross-site data. 73 | 74 | Merchants often delegate payment for goods and services to third-party payment providers, and merchants integrate with those providers by embedding a button into their site. However, payment providers on the Web today often decorate their buttons with information specific to the user, such as the last four digits of their credit card, or the card’s carrier (like Visa or MasterCard). This assures the user visiting the merchant that their transaction will occur smoothly. If the user is more confident in their purchase experience, this benefit will then be passed onto the businesses of the payments provider and the merchant. 75 | 76 | Currently, this experience relies on unpartitioned user data (like third-party cookies) being available across sites. Once the user’s card data is stored by the payment provider in a first-party context, it needs to be accessible to their payment buttons embedded in third-party contexts. Fenced frames seek to re-enable this use case via the “local unpartitioned data access” proposal, which can be found in this [explainer](https://github.com/WICG/fenced-frame/blob/master/explainer/fenced_frames_with_local_unpartitioned_data_access.md) document. Here’s a brief summary: 77 | 78 | 79 | 80 | 1. Fenced frames will be allowed to read data from Shared Storage outside of a worklet via `sharedStorage.get()`, and they can use that data to personalize the content of the frame. 81 | 2. This data cannot be directly exfiltrated to the embedder given fenced frames’ isolation mechanisms, but it could still be sent over the network. As a result, calling `sharedStorage.get()` will not be allowed until the frame’s document has its network access revoked by resolving a call to `window.fence.disableUntrustedNetwork()`. Network access removal encompasses navigation, subresource fetches, alternative networking APIs like Websockets, and special fenced frame mechanisms like event-level reporting. 82 | 3. The cross-site data will remain local to the frame while still allowing a personalized experience for the user. If the frame’s document needs to communicate to the embedder that the user clicked on the content, it can do so via the new `window.fence.notifyEvent()` API. This fires an event at the `HTMLFencedFrameElement` in the embedder containing no cross-site information, which in the case of payment buttons can be used to initiate the checkout flow on the merchant site. 83 | 84 | For an end-to-end example of how this setup could work in practice, take a look at this sample code in the [explainer](https://github.com/WICG/fenced-frame/blob/master/explainer/fenced_frames_with_local_unpartitioned_data_access.md#code-example). 85 | 86 | 87 | This “local unpartitioned data access” mode can be enabled on every type of fenced frame, whether they were constructed with a redacted `FencedFrameConfig` or a plaintext URL. Once the frame has disabled network access, all types of fenced frames should be able to benefit from content personalization to support relevant use cases. 88 | 89 | 90 | ## Manual Construction for General Purpose Usage and Testing 91 | 92 | The Protected Audience API and the Shared Storage API rely upon a redacted `FencedFrameConfig` to render the fenced frame. This is because the frame is constructed via cross-site data brokered by the browser, and the opacity ensures that the embedder does not access that sensitive data in any way. However, what if the frame does not need to be constructed using cross-site data, or it only uses cross-site data after disabling network access as described in the above section? 93 | 94 | Example scenarios include: 95 | 96 | 97 | 98 | * A web developer is prototyping a site that will render ads in fenced frames, but wants to test their placement with sample content before integrating with the Protected Audience API. 99 | * A third-party payments provider currently embeds a personalized button as described above, but personalization only occurs after calling `window.fence.disableUntrustedNetwork()`. 100 | * A developer for a merchant site wants to integrate with that payments provider, and needs to test that their payment flow still works when a fenced frame is used. 101 | 102 | In these cases, the developer does not need to rely on a config-generating API. They likely know the exact URL of the content that they want to embed, and the URL is not constructed from cross-site data. To meet these needs, fenced frames are also manually constructable: 103 | 104 | const frame = document.createElement("fencedframe"); 105 | const config = new FencedFrameConfig("https://example.com/"); 106 | frame.config = config; 107 | document.body.append(frame); 108 | 109 | 110 | In addition to allowing smoother adoption of fenced frames in a testing environment, manual construction will allow documents loaded from a known URL to get all of the isolation benefits of fenced frames for free. This presents a clear privacy advantage in situations where communication with the embedder is not essential to the page’s functionality. 111 | 112 | In Chrome, manual construction is currently behind a flag. To test it out, enable the following experiments in `chrome://flags` and then reopen the browser. 113 | 114 | 115 | 116 | * Privacy Sandbox Ads APIs (`chrome://flags/#privacy-sandbox-ads-apis`) 117 | * Enable the `FencedFrameConfig` constructor (`chrome://flags/#enable-fenced-frames-developer-mode`) 118 | -------------------------------------------------------------------------------- /meetings/TPAC2024Notes.md: -------------------------------------------------------------------------------- 1 | 2 | **Breakout notes for https://github.com/w3c/tpac2024-breakouts/issues/40** 3 | 4 | Attendees 5 | 6 | Shivani Sharma (Google Chrome) 7 | 8 | Andrew Verge (Google Chrome) 9 | 10 | Zachary Cancio (Google Chrome) 11 | 12 | Josh Karlin (Google Chrome) 13 | 14 | Ilya Grigorik (Shopify) 15 | 16 | Joel Antoci (Shopify) 17 | 18 | Dominic Farolino (Google Chrome) 19 | 20 | Sarah Murphy (Microsoft Edge) 21 | 22 | Anusha Muley (Google Chrome) 23 | 24 | Mustaq Ahmed (Google Chrome) 25 | 26 | Kaustubha Govind (Google Chrome) 27 | 28 | Fatma Moalla (Criteo) 29 | 30 | Maxime Vono (Criteo) 31 | 32 | Michael Kleber (Google Chrome) 33 | 34 | Agenda 35 | 36 | Slides: https://docs.google.com/presentation/d/1xKwCrhN2pD_lxuPfurgjEDkfyAcf3wgxPS9njlG9tT0/edit?usp=sharing 37 | 38 | Notes 39 | 40 | Shivani (from the slides linked above): 41 | 42 | 43 | 44 | * Last TPAC talked about high level design. 45 | * We will be demoing functionality 46 | * Explainer in Q4; intent to prototype on blinkdev 47 | * everything partitioned by top-level site. but cross-site data is shown the user. where the data is shown and the rest of the page are isolated. iframes have communication channels like postmessage and side channels. for colluding parties to transfer info. 48 | * Fenced frames is a new HTML element that allows embedding documents. privacy flow of the use case governs whats possible to communicate between fenced page and embedded page 49 | * FF no post message; any partition for storage is ephemeral and unique (no same origin frame including other fenced frames) Window.top do not point to the top-level but the FF root frame. THere is a tree that starts at the primary top-level. and. another root which is the FF tree. 50 | * FencedframeConfig - provides functionality like protected audience. ad not available to anyone outside the FF. FF config makes the url opque to the outside page. But we are not going into PA details in this session. 51 | * In another way of creating the FencedFrameConfig, embedding context can actually provide the source URL (its not hidden between the two contexts). but when the fenced frame gets access to cross-site data; need to make sure the data cannot leave the FF. 52 | * New API -> window.fence.disableUntrustedNetwork. FF can voluntarily give up network access and then can access cross-site data. 53 | * Personalized Payment Buttons. UX setting can choose to disable this feature. 54 | * Provider Payment; example.pay. go to the top-level and give CC info. At a later time , example.pay wants to show the last 4 of CC on another merchant site. example.pay can write to shared storage when user provided it. Shared Storage data is stored on origin scoped basis and read in restricted contexts. FF without network can read from shared storage - a new output gate for Shared Storage 55 | * Each payment provider on a page could use the last 4 to give user awareness. 56 | * When the button is created its in a FF not in an iframe. 57 | * embedding context creates an example.pay FF; FF in state 1 has network can get the html document js/css/. In state 2 it will call disable network. Then can call storage access from example.pay. 58 | * new click listener/notify API to tell the embedding page. Embedding page handles click. 59 | * New API surfaces. 60 | * FF config constructor. 61 | * DisableUntrustedNetwork() . invovled anything that involves network access, any navigations, new tabs, etc. 62 | * A lot of srfuaces blocked via network isolation key's nonce. Reuse nonce in key to uniquely identify requests coming from FF tree. if nonces match request that have been blocked. 63 | * Nested iframes cannot do network access as well. 64 | * Wait for all nested FF to call disableUntrustedNetwork. 65 | * Some networks might be OK like private aggregation API 66 | * Any request the browser makes are OK 67 | * sharedStorage.get() already exists. This FF with no network can call it. SharedStorage write anywhere, read with restrictions. 68 | * Guards: permission policy; user has not disabled feature via UX; Privacy Sandbox's attestation. 69 | 70 | Alex Christenson: 71 | 72 | 73 | 74 | * trades network access for getting shared acces. 75 | * Locally only already isolated. Can only tell the outside page that a click happened 76 | 77 | 78 | 79 | Sarah: 80 | 81 | 82 | 83 | * is the storage cached at all. User refreshes page; FF data is cached. 84 | 85 | * Shared Storage needs to be gotten again. 86 | 87 | 88 | 89 | Joel Anotic: 90 | 91 | 92 | 93 | * FF are opaque from each other. 94 | * Two same FF reading same origin. 95 | 96 | 97 | 98 | Sarah: 99 | 100 | * there is a write mode. 101 | 102 | Shivani: 103 | 104 | Even if the FF writes something to shared storage, it has to give up network access again to read that data. 105 | 106 | 107 | 108 | Michael: 109 | 110 | sharing of shared storage is domain A"s data while the user is on domain C. but all domain A's storage. 111 | 112 | 113 | 114 | Fatima (Criteo): 115 | 116 | * read shared storage from a protected audience auction 117 | 118 | 119 | 120 | Isaac: 121 | 122 | part of privacy sandbox 123 | 124 | 125 | 126 | Michael: 127 | 128 | not possible to bid based on cross-site user profile. Shared storage could let use create user porofile but does not let you use it for bidding. its a different output gate. Output gate is controlled. The output from Shared Storage can be fed from aggregation. Private aggregation APi is a differn output gage 129 | 130 | 131 | 132 | Ilya (shopify): 133 | 134 | 135 | 136 | * Is there limit on data. Can call a 137 | * Click [Andrew: Will cover on next slide] 138 | 139 | 140 | 141 | Josh: 142 | 143 | 144 | 145 | * 5mb limit. Not part of quota. 146 | * On previous question: If i read from FF and stored something locally. Each FF has an opaque storage key and can't persist local storage. 147 | 148 | Andrew 149 | 150 | 151 | 152 | * Today its the embedder to intiiate the payment flow. need to tell embedder click occurred. 153 | * window.fence.notifyEvent 154 | * Event paramater is dom event object. Click only event type, could support more if addiitonal use cases. 155 | * JS running the FF. Only have event called on legitmate user action. 156 | * When function called. new tree. no context of click, no coordinates or timestamp. 157 | * Using other payments. FF needs transient user activation. User activation will be delegated to the embedder and consumed by the API. Delegate the permission to the window. 158 | 159 | John (Apple) 160 | 161 | What actual usage. Click in the frame. 162 | 163 | Andrew: 164 | 165 | * user click preregistered paymenmt info. 166 | 167 | John: 168 | 169 | * how does the top frame know where to open a popup? 170 | 171 | Shivani: 172 | 173 | * the top-frame/embedding frame has some knowledge since it provided the URL in the first place. 174 | 175 | Michael: 176 | 177 | Possibly Iframe owned by payment provider, that initiates transaction. Inside of iframe is FF that shows pixels that shows x1234. 178 | 179 | John: 180 | 181 | inherent knoweldge from first iframe. There could be confusion there. 182 | 183 | Michael: 184 | 185 | this is a feature, if user turn it off, then use generic info. 186 | 187 | John: 188 | 189 | whats if theres an error in loading. the first iframe would be 190 | 191 | Shivani: 192 | 193 | the embedding context is the one to set the URL. 194 | 195 | Michael/Andrew 196 | 197 | The network in stage 1 confirms loading. If the user clicks but nothing was loaded in the first place, then API can't be called. 198 | 199 | Josh (Google): 200 | 201 | load default generic, and opportunistically show something personalized. Not useful for ads. 202 | 203 | 204 | 205 | Michael: 206 | 207 | * don't have a use case in hand that's helpful for adtech 208 | 209 | Josh: 210 | 211 | using in an ad would be a new output gate for shared storage. 212 | 213 | John W (Apple): 214 | 215 | i'm going to show an ad for this game; player maybe already plays that game. show a "level 5" copy. 216 | 217 | Miachel: 218 | 219 | top-level can't distinguish. 220 | 221 | 222 | 223 | Andrew: 224 | 225 | open the top-level, then the user can know. 226 | 227 | Mustaq: 228 | 229 | only a single button is allowed? 230 | 231 | Isaac (microsoft): 232 | 233 | ad-tech surrending network access for video; video player styling. 234 | 235 | Michael: 236 | 237 | 238 | 239 | * Can be used for something like using the font for native. Seems to be difficult use case. 240 | * Payment use case 241 | 242 | Josh: 243 | 244 | 245 | 246 | * Disable untrusted network, since the FF can't talk. Could allow the postmessage in but not out. 247 | * Could we use this for selecting an ad, not covered here. 248 | 249 | Andrew: 250 | 251 | * visit payment provider in 1p context. Store CC on backend. On success. This info should be written to shared storage. Writing in any ocntext. reading thats limited. 252 | 253 | * Window.sharedStorage.set. 254 | 255 | * user visits merchant site. The merchant site will delegate a 3rd party script or API that loads the FF. (example.pay.createButton()). Script creates payment button. 256 | 257 | * inside is where the FF occurs. FFconfig is used to navigate. Directed to example.pay/buttonURL. Registere that FF click event listener. Would kick off in embedder when clicked. 258 | 259 | * disablenetwork 260 | 261 | * accesssharedstorage 262 | 263 | * handle click event. 264 | 265 | * usePromise to get info out of shared storage. Document in FF would attach eventListener. window.notify. 266 | 267 | * Demo 268 | 269 | * regsiter card on example.py 270 | 271 | * go to merchant page. Button that loaded after, shows card network and last 4. 272 | 273 | * when clicked, embedder page can handle click. 274 | 275 | * privacy, multiple buttons 276 | 277 | * You can have multiple buttons, but call to embedder would be indistinguishable. Only the fence frame root can call notify even to the parent. Only the same signal will occur regardless of which one you click. Trying to limit knowledge gained from click. Click is one-bit leak. Multiple clicks based based on whats rendered could be used. if 8 frames, only one prompts the user, user clicks. effectively learn 3 bits of data. Mitigations.. rate limting frames from origin on one particular page. Cap number of bits learned per click. How related is too related between fenced frames. 278 | 279 | Michael: 280 | 281 | * When a click happens, the JS has to propagate. busy waits what ms. 282 | 283 | P2: 284 | 285 | Michael: ms 439; at .439 is at which time i call to the dispatch. How much can the parent know. [Andrew: The timestamp is not revelaed.] The parent page is going to receive an event. 286 | 287 | Ilya Grigorik (Shopify): 288 | 289 | Thank You. Very interested in the personalization use case. payments. personalized sign-in button. Variety of other personalization frames that merchant provide: delivery promises. use geoIP approx. FF could have some info about the user like zip; then FF could do promise calculation. Powerful buiding block. Membership signals. Offer discounts to students/vets. At the very end. Use this service to prove you're a member. 290 | 291 | Josh: 292 | 293 | like that. use 100% off. user clicks, then shopify can validate. 294 | 295 | 296 | 297 | Ilya: 298 | 299 | * if amazon knows you're in prime, can show a different promise. Shopify know you're a student can show something. 300 | 301 | Joel: 302 | 303 | FedCM give the suer understanding they are signed; by clicking will go through lower friction. Does not require full auth. 304 | 305 | Shivani: 306 | 307 | follow up in a Github issue. 308 | 309 | Ilya: 310 | 311 | Where do other browsers stand? 312 | 313 | John (Apple): 314 | 315 | interested in technology. don't have implementation, experimental. Like properties. Pieces of this interested beyond this spec. 316 | 317 | Sarah: 318 | 319 | msft edge. chromium embedder. definitely experiemnt 320 | 321 | Isaac: 322 | 323 | Question to John: not fenced frame referring to shared stroage ? 324 | 325 | John: 326 | 327 | isolating cross-site. have guarantees beyond this. 328 | 329 | small devices that are battery powered want them to last a week. 330 | 331 | is shared storage required? 332 | 333 | Shivani: 334 | 335 | yes, shared storage is in this case. 336 | 337 | Michael: 338 | 339 | without shared storage, after you give up network access could call something like requestStorageAccess? 340 | 341 | John: 342 | 343 | iframe sandbox; site isolation; another way to isolate cross-site data. You could still have storage, you could still have partition. 344 | 345 | Shivani: 346 | 347 | could be a local storage unpartitioned storage bucket. 348 | 349 | Michael: 350 | 351 | haven't talked about cookie access 352 | 353 | Shivani: 354 | 355 | cookies not good bc it goes on the network. 356 | 357 | Michael: 358 | 359 | talk about other variants. Would be interested in discussing how Apple would want to solve this 360 | 361 | John Delaney: 362 | 363 | this is only using basic shared storage. 364 | 365 | Shivani: 366 | 367 | to implemnet shared storage, just need the simplest version. 368 | 369 | Michael: 370 | 371 | don't have all the features jsut a shared db with write and controlled read. 372 | 373 | Josh: 374 | 375 | requestStorageAccess could be auto-granted if network disabled FF. esp for localStorage. 376 | -------------------------------------------------------------------------------- /w3c.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": [80485], 3 | "contacts": ["yoavweiss"], 4 | "repo-type": "cg-report" 5 | } --------------------------------------------------------------------------------