From 689776fafee28d39740b67ea27dfd674ee8e2da6 Mon Sep 17 00:00:00 2001 From: Andrew Verge Date: Fri, 12 Apr 2024 14:49:29 -0400 Subject: [PATCH 01/38] Add specific click API details, plus a code example (#144) * Add specific click API details, plus a code example Now that we've solidified some of the API designs, we should have more details about them in the explainer where necessary. Getting from shared storage is pretty straightforward, but the click listener API needs an explicit description of its API surface. In addition, I've added an end-to-end example of how all of our API surfaces can be combined for a real-world use case of personalized payment buttons. * Respond to first round of comments. * Remove line referencing "cancellable" field * Small grammar and formatting fixes * Update description of onfencedtreeclick. * Reword onfencedtreeclick description --- ...es_with_local_unpartitioned_data_access.md | 138 ++++++++++++++++-- 1 file changed, 129 insertions(+), 9 deletions(-) diff --git a/explainer/fenced_frames_with_local_unpartitioned_data_access.md b/explainer/fenced_frames_with_local_unpartitioned_data_access.md index 850c113f..572f5502 100644 --- a/explainer/fenced_frames_with_local_unpartitioned_data_access.md +++ b/explainer/fenced_frames_with_local_unpartitioned_data_access.md @@ -139,25 +139,148 @@ Certain privacy preserving aggregated reports can be allowed from the fenced fra ## Click listener API -The exact surface of the API is still being designed, but at a high level, there will be 2 parts to this API surface: +The click listener API is broken into two parts: +* The embedding context will invoke `addEventListener()` on the `HTMLFencedFrameElement` to listen for a click event on the fenced frame. +* 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. +### Changes to HTMLFencedFrameElement -* The embedding context will invoke an API on the fenced frame element to listen for a click event on the fenced frame. -* An API that a script inside the fenced frame tree can invoke which will trigger the embedding context’s click event listener. +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. +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. -### Click Privacy considerations +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: -Since this is exfiltrating some information (that a click happened) outside the fenced frame, we will need to consider the following privacy considerations: +* It will be fired using the base DOM Event constructor, rather than a new event subclass. +* It will be initialized with a type parameter of `'fencedtreeclick'` +* 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`, + so user agents can choose a suitable value to use, such as the Unix epoch. +* The event's `isTrusted` field will be true, to indicate that the event is dispatched by the user agent. +* All other attributes of the event object will have the default settings of a newly-constructed event object. +* When the event object is dispatched, its target will always be the `HTMLFencedFrameElement` upon which the event listener was registered. + +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. + +### Changes to window.fence + +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: + +* `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. +* `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. + +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. + +Here's an example of how `window.fence.notifyEvent()` should be used: + +```javascript +// In the embedder: + +// Make a fenced frame +let fencedframe = ... +fencedframe.addEventListener('fencedtreeclick', () => { + alert('hello world!'); +}); +// In the embedded content: + +document.body.addEventListener('click', (e) => {} { + // Fire a "fencedtreeclick" event at the embedder. + window.fence.notifyEvent(e); +}); +``` + +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. + +### Click Privacy considerations + +Since this is exfiltrating some information (that a click happened) outside the fenced frame, we will need to consider the following privacy considerations: -* The click event that is notified to the embedding frame should not carry any additional data like the click coordinates. * 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). * 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/). +## Code Example + +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. + +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. + +```javascript +// When a user navigates to “examplepay.com” and registers their credit card, the last +// four digits of their card are written to Shared Storage. + +// On https://examplepay.com +async function registerCard() { + // Prepare HTTP request with user-provided card infomation. + let request = createCardRegistrationRequest({number: 'XXXX XXXX XXXX 1234', + expDate: 'MM/YY', ...}); + + // Register the card information with examplepay.com. + let response = await fetch(request); + + // If the card was registered successfully, write the last 4 digits of the + // card number to Shared Storage for origin "examplepay.com." The data to + // write could come from the response body, a 1p cookie in a response header, + // or somewhere else. + if (response.status === 200) { + let body = await response.json() + await window.sharedStorage.set('last4', body.last4); + console.assert(body.last4 === '1234'); + } +} + +// Once the value has been written to Shared Storage, it can later be read inside a +// fenced frame, but only when that frame is same-origin to examplepay.com and has +// its network access restricted. Here’s what that would look like on a merchant page: + +// On merchant page +let example_pay_button = examplePayAPI.createButton(); +document.body.appendChild(example_pay_button); + +// In examplePayAPI +function createButton() { + let fenced_frame = document.createElement('fencedframe'); + // Create a fenced frame config using a URL directly instead of a config-generating + // API like Protected Audience or sharedStorage.selectURL(). Note that the URL is + // same-origin to the site where the card was first registered. + fenced_frame.config = new FencedFrameConfig('https://examplepay.com/make_button'); + + // Registering a "fencedtreeclick" event handler on the fenced frame element allows + // it to respond to a "click" event that fires inside the frame's content. + fenced_frame.addEventListener('fencedtreeclick', () => { + startPaymentFlow(); + }); + return fenced_frame; +} + +// In the "https://examplepay.com/make_button" fenced frame document +function personalizeButton () { + // By waiting for the page to finish loading, we can ensure that there's + // no additional JS waiting to execute before revoking network. + window.onload = async () => { + // First, disable untrusted network access in the fenced frame. + await window.fence.disableUntrustedNetwork(); + + // Read the last four digits of the card from Shared Storage + // and render them in a button. + b = document.createElement('button'); + b.textContent = await window.sharedStorage.get('last4'); + + // Tell the embedder that the button was clicked, so that the payment flow can be + // initiated. This will fire a "fencedtreeclick" event at the fenced frame element + // in the embedder, which we previously registered a handler for. + b.addEventListener('click', (e) => { + window.fence.notifyEvent(e); + }); + + document.body.appendChild(b); + } +} +``` + + ## Privacy considerations This section goes into the privacy considerations of the 2 states a fenced frame can be in: @@ -205,7 +328,6 @@ _“We had a long discussion about how the shape of this, changing the relations _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?”_ - ## Alternatives considered **Alternatives considered: Cookies** @@ -226,8 +348,6 @@ The benefits of using cookies for this solution are the following: * The cookies being a default network concept does not align well with this change where the “fenced” cookies have to be JS-only. * 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. - - **Alternatives considered: Local Storage** [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: From 28bf4ba20e4a881701b82f2593e1e138c304fa48 Mon Sep 17 00:00:00 2001 From: Garrett Tanzer Date: Mon, 15 Apr 2024 18:55:14 -0400 Subject: [PATCH 02/38] Add bit about top-level navigation metrics (#154) * Add bit about top-level navigation metrics * Address comment --- explainer/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/explainer/README.md b/explainer/README.md index cf811f00..877054f0 100644 --- a/explainer/README.md +++ b/explainer/README.md @@ -179,7 +179,7 @@ The fenced frame’s main goal is to improve privacy by disallowing communicatio * **IntersectionObserver:** It is important for ads reach and reporting APIs to know the status of the ad frame's visibility, so IntersectionObserver will need to be supported in some way, for instance by only letting it be consumed by browser APIs like [aggregate reporting API](https://github.com/csharrison/aggregate-reporting-api). We can't fully support it as iframes do, to make sure that embedding sites do not (re)position frames such that IntersectionObserver is used for communicating the user’s id to the fenced frame. This is currently under design and intersection observer capability will be supported until the alternative is provided. * **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. Also delegation of permissions from the embedding context to the fenced frames should not be allowed as that could be a communication channel. This is detailed further [here](https://github.com/shivanigithub/fenced-frame/blob/master/explainer/permission_document_policies.md). * **Network side channel:** This is detailed more here: [network side channel](https://github.com/shivanigithub/fenced-frame/blob/master/explainer/network_side_channel.md) -* **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 mitgations going forward (currently being brainstormed). Additionally, this is vulnerable to the network side channel as mentioned above when the embedding site and destnation site are colluding. +* **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. More of these channels exist and the [integration with web platform](https://github.com/shivanigithub/fenced-frame/blob/master/explainer/integration_with_web_platform.md) details them further. From 72faa40181bd227988d2e3ca6521808205d36a12 Mon Sep 17 00:00:00 2001 From: Garrett Tanzer Date: Tue, 16 Apr 2024 09:44:56 -0400 Subject: [PATCH 03/38] Add IntersectionObserver metrics bit (#153) * Add IntersectionObserver metrics bit * Address half of comment * Update explainer README --- explainer/README.md | 2 +- explainer/integration_with_web_platform.md | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/explainer/README.md b/explainer/README.md index 877054f0..77ff375f 100644 --- a/explainer/README.md +++ b/explainer/README.md @@ -176,7 +176,7 @@ The fenced frame’s main goal is to improve privacy by disallowing communicatio * **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. -* **IntersectionObserver:** It is important for ads reach and reporting APIs to know the status of the ad frame's visibility, so IntersectionObserver will need to be supported in some way, for instance by only letting it be consumed by browser APIs like [aggregate reporting API](https://github.com/csharrison/aggregate-reporting-api). We can't fully support it as iframes do, to make sure that embedding sites do not (re)position frames such that IntersectionObserver is used for communicating the user’s id to the fenced frame. This is currently under design and intersection observer capability will be supported until the alternative is provided. +* **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. * **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. Also delegation of permissions from the embedding context to the fenced frames should not be allowed as that could be a communication channel. This is detailed further [here](https://github.com/shivanigithub/fenced-frame/blob/master/explainer/permission_document_policies.md). * **Network side channel:** This is detailed more here: [network side channel](https://github.com/shivanigithub/fenced-frame/blob/master/explainer/network_side_channel.md) * **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. diff --git a/explainer/integration_with_web_platform.md b/explainer/integration_with_web_platform.md index 7aded614..a570abf9 100644 --- a/explainer/integration_with_web_platform.md +++ b/explainer/integration_with_web_platform.md @@ -11,7 +11,8 @@ The origin of the fenced frame will be the regular origin that it got navigated 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. ## Viewability -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. Viewability events are important information in the ads workflow for conversion reports and payments and would be made available in FLEDGE and other ads use cases via separate mechanisms. In the first origin trial of fenced frames, intersection observer will be fully supported and it will be phased out only when the alternative mechanism is launched. +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. +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. ## Visibility 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/shivanigithub/fenced-frame/blob/master/explainer/network_side_channel.md). From 19618e34fc066aded66ae9c360457d17bf608728 Mon Sep 17 00:00:00 2001 From: Shivani Sharma Date: Fri, 19 Apr 2024 17:42:40 -0400 Subject: [PATCH 04/38] Update network_side_channel.md Reorganizing the document for better flow. Highlighting the prerequisites. --- explainer/network_side_channel.md | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/explainer/network_side_channel.md b/explainer/network_side_channel.md index d9dbdaa5..56816ead 100644 --- a/explainer/network_side_channel.md +++ b/explainer/network_side_channel.md @@ -1,17 +1,31 @@ # Network side channel -Consider the following network side channel leak: +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. + +**Prerequisites of this attack** + +This side channel relies on the following factors being true: +* There are colluding servers that are joining logs to be able to create cross-site user profiles. +* There is common information available in the fenced frame context and the outer context. This is trivially available information like: + * creation time of the fenced frame/ network request time, + * IP address of the client. +* 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. + +**Example** + +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". +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. + +Consider the following example information flow: * 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. -* The fenced frame is created and has access to user specific information X (e.g. user’s interest group for TURTLEDOVE). When the fenced frame document’s resources are requested from site B, X is also sent along. B can also let tracker.example know. The tracking site tracker.example can then correlate using the time/IP address bits of both requests. +* 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. +* The tracking site tracker.example can then correlate using the time/IP address bits of both requests. * A can then know X via tracker.com -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 interacting with the fenced frame e.g. in the "opaque-ads" mode. -The common bits of information for such an attack are: -* Network timing -* IP address correlation between frames +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. ## Mitigations These issues are not unique to fenced frames and also exist in cross-site navigations today so they could either depend on future solutions to these for cross-site navigations e.g. [Gnatcatcher](https://github.com/bslassey/ip-blindness), or could 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. -Both the opaque-ads consumers, FLEDGE and SharedStorage will guarantee k-anonymity of the URL used to create the fenced frame. + From e5a4cdf18185c29710d342873452e3659b522c35 Mon Sep 17 00:00:00 2001 From: Shivani Sharma Date: Fri, 19 Apr 2024 18:00:23 -0400 Subject: [PATCH 05/38] Update IP protection explainer link --- explainer/network_side_channel.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/explainer/network_side_channel.md b/explainer/network_side_channel.md index 56816ead..ac86fc08 100644 --- a/explainer/network_side_channel.md +++ b/explainer/network_side_channel.md @@ -27,5 +27,5 @@ The above is an example of a scenario where user id on A and user’s informatio ## Mitigations -These issues are not unique to fenced frames and also exist in cross-site navigations today so they could either depend on future solutions to these for cross-site navigations e.g. [Gnatcatcher](https://github.com/bslassey/ip-blindness), or could 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. +These issues are not unique to fenced frames and also exist in cross-site navigations today so they could either depend on future solutions to these for cross-site navigations e.g. [IP Protection](https://github.com/GoogleChrome/ip-protection/), or could 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. From 90c42a1a5b8ea64a01f9245e9d81920433307351 Mon Sep 17 00:00:00 2001 From: Shivani Sharma Date: Fri, 26 Apr 2024 17:40:32 -0400 Subject: [PATCH 06/38] Update to use Protected Audience --- explainer/fenced_frame_config.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/explainer/fenced_frame_config.md b/explainer/fenced_frame_config.md index 345e4433..99d95ce3 100644 --- a/explainer/fenced_frame_config.md +++ b/explainer/fenced_frame_config.md @@ -3,7 +3,7 @@ ## Introduction -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 [FLEDGE](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. +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. ## Proposed solution @@ -13,9 +13,9 @@ For use cases involving APIs that access cross-site data, we need to be able to 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. -### Turtledove Example +### Protected Audience Example -When the SSP JS invokes the Turtledove 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. +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. ``` @@ -33,6 +33,7 @@ navigator.runAdAuction(myAuctionConfig).then((auctionWinnerConfig) => { ## Backwards compatibility 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. +Update: The `src` attribute is no longer supported on fenced frames. ## Embedder context From dbb22ca0f8c3e17aba439a6dc343777002101e55 Mon Sep 17 00:00:00 2001 From: Liam Brady Date: Wed, 1 May 2024 17:38:20 -0400 Subject: [PATCH 07/38] Spec cross-origin reportEvent() support (#152) --- spec.bs | 75 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 15 deletions(-) diff --git a/spec.bs b/spec.bs index 7d580e4e..fcc5984b 100644 --- a/spec.bs +++ b/spec.bs @@ -1145,7 +1145,10 @@ A fenced frame config is a [=struct=] with the following [=str :: null, or a [=string=] : is ad component - :: A [=boolean=]. Defaulting to false. + :: A [=boolean=], initially false. + + : cross-origin reporting allowed + :: A [=boolean=], initially false. Note: When true, this [=fenced frame config=] reprsents an ad component. An ad component can be @@ -1199,6 +1202,9 @@ A fenced frame config instance is a [=struct=] with the follow : is ad component :: A [=boolean=], initially false. + + : cross-origin reporting allowed + :: A [=boolean=], initially false.
@@ -1283,6 +1289,9 @@ A fenced frame config instance is a [=struct=] with the follow : [=fenced frame config instance/is ad component=] :: |config|'s [=fenced frame config/is ad component=] + + : [=fenced frame config instance/cross-origin reporting allowed=] + :: |config|'s [=fenced frame config/cross-origin reporting allowed=]
Each [=browsing context=] has a fenced frame config instance, @@ -1498,11 +1507,18 @@ Several APIs specific to fenced frames are defined on the {{Fence}} interface. DOMString eventType; DOMString eventData; sequence<FenceReportingDestination> destination; - + + // Determines if this data can be sent in a reportEvent() beacon or automatic + // beacon that originates from a document that is cross-origin to the mapped + // URL of the fenced frame config that loaded this frame tree. + // Note that automatic beacon data can only be set from documents that are + // same-origin to the fenced frame config's mapped URL, so this effectively + // opts in the data to being used in a cross-origin subframe. + boolean crossOriginExposed = false; + // When setting event data to be used later in an automatic beacon, the // following properties are used: boolean once = false; - boolean crossOriginExposed = false; // When reporting to a custom destination URL (with substitution of macros defined by // the Protected Audience buyer), the following property is used: @@ -1529,19 +1545,31 @@ Several APIs specific to fenced frames are defined on the {{Fence}} interface. 1. If |instance|'s [=fenced frame config instance/is ad component=] is true, then return. - 1. If the [=relevant settings object=]'s [=environment settings object/origin=] and |instance|'s - [=fenced frame config instance/mapped url=]'s [=url/origin=] are not [=same origin=], then - return. - 1. If |instance|'s [=fenced frame config instance/fenced frame reporter=] is null, then return. - 1. If |event| is a {{DOMString}}, run [=report a private aggregation event=] using |instance|'s - [=fenced frame config instance/fenced frame reporter=] with |event|. + 1. If |event| is a {{DOMString}}: + + 1. If [=this=]'s [=relevant settings object=]'s [=environment settings object/origin=] and + |instance|'s [=fenced frame config instance/mapped url=]'s [=url/origin=] are not [=same + origin=], then return. + + 1. Run [=report a private aggregation event=] using |instance|'s [=fenced frame config + instance/fenced frame reporter=] with |event|. 1. If |event| is a {{FenceEvent}}: 1. If |event|'s {{FenceEvent/eventType}} [=string/starts with=] "`reserved.`", then return. + 1. If all of the following conditions are true: + + * [=this=]'s [=relevant settings object=]'s [=environment settings object/origin=] and + |instance|'s [=fenced frame config instance/mapped url=]'s [=url/origin=] are not [=same + origin=]; + * either |event|'s {{FenceEvent/crossOriginExposed}} is false or |instance|'s + [=fenced frame config instance/cross-origin reporting allowed=] is false; + + then return. + 1. If |event| has a {{FenceEvent/destinationURL}}: 1. If |event| has a {{FenceEvent/destination}} or a {{FenceEvent/eventType}} or a {{FenceEvent/eventData}}: @@ -1595,6 +1623,17 @@ Several APIs specific to fenced frames are defined on the {{Fence}} interface. /fenced-frame/fence-report-event.https.html /fenced-frame/fence-report-event-destination-url.https.html + /fenced-frame/fence-report-event-cross-origin-content-initiated.https.html + /fenced-frame/fence-report-event-cross-origin-nested-urn-iframe.https.html + /fenced-frame/fence-report-event-cross-origin-nested.https.html + /fenced-frame/fence-report-event-cross-origin-no-embedder-opt-in.https.html + /fenced-frame/fence-report-event-cross-origin-no-subframe-opt-in.https.html + /fenced-frame/fence-report-event-cross-origin-urn-iframe-content-initiated.https.html + /fenced-frame/fence-report-event-cross-origin-urn-iframe-no-embedder-opt-in.https.html + /fenced-frame/fence-report-event-cross-origin-urn-iframe-no-subframe-opt-in.https.html + /fenced-frame/fence-report-event-cross-origin-urn-iframe.https.html + /fenced-frame/fence-report-event-cross-origin.https.html + /fenced-frame/fence-report-event-sub-fencedframe.https.html @@ -1613,9 +1652,9 @@ Several APIs specific to fenced frames are defined on the {{Fence}} interface. 1. If |instance| is null, then return. - 1. If the [=relevant settings object=]'s [=environment settings object/origin=] and |instance|'s - [=fenced frame config instance/mapped url=]'s [=url/origin=] are not [=same origin=], then - return. + 1. If [=this=]'s [=relevant settings object=]'s [=environment settings object/origin=] and + |instance|'s [=fenced frame config instance/mapped url=]'s [=url/origin=] are not [=same + origin=], then return. 1. If |instance|'s [=fenced frame config instance/fenced frame reporter=] is null, then return. @@ -1649,9 +1688,9 @@ Several APIs specific to fenced frames are defined on the {{Fence}} interface. 1. If |instance| is null, then return. - 1. If the [=relevant settings object=]'s [=environment settings object/origin=] and |instance|'s - [=fenced frame config instance/mapped url=]'s [=url/origin=] are not [=same origin=], then - return. + 1. If [=this=]'s [=relevant settings object=]'s [=environment settings object/origin=] and + |instance|'s [=fenced frame config instance/mapped url=]'s [=url/origin=] are not [=same + origin=], then return. 1. If |instance|'s [=fenced frame config instance/nested configs=] is null, then return. @@ -2740,6 +2779,12 @@ content in the <{fencedframe}> or its embedder, exactly one of two things will h [=navigation params/fenced frame config instance=] being non-null) always cause a [[#bcg-swap]]. + 1. Set |navigationParams|'s [=navigation params/fenced frame config instance=]'s [=fenced frame + config/cross-origin reporting allowed=] to the result of running [=header list/get a + structured field value=] on |navigationParams|'s [=navigation params/response=]'s + [=response/header list=] given "Allow-Cross-Origin-Event-Reporting" and + "`item`". + 1. Set |browsingContext|'s [=browsing context/fenced frame config instance=] to |navigationParams|'s [=navigation params/fenced frame config instance=]. From 46c479e01d741dfab8429bc18e5f3193e4fd6db0 Mon Sep 17 00:00:00 2001 From: Liam Brady Date: Wed, 8 May 2024 16:31:06 -0400 Subject: [PATCH 08/38] Add web platform-exposed FencedFrameConfig constructor (#137) --- spec.bs | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/spec.bs b/spec.bs index fcc5984b..2501a27e 100644 --- a/spec.bs +++ b/spec.bs @@ -464,15 +464,19 @@ The config IDL attribute getter Note: This holds because when the element has been removed from the DOM, its removal steps immediately destroy the [=fenced navigable container/fenced navigable=]. - 1. Let |urn uuid| be the given {{FencedFrameConfig}}'s [=fencedframeconfig/urn=]. + 1. Let |navigation url or urn| be the given {{FencedFrameConfig}}'s [=fencedframeconfig/url=] if + the given {{FencedFrameConfig}}'s [=fencedframeconfig/url=] is not null, and the given + {{FencedFrameConfig}}'s [=fencedframeconfig/urn=] otherwise. + + 1. If |navigation url or urn| is failure, then return. 1. Let |shared storage context| be the given {{FencedFrameConfig}}'s [=fencedframeconfig/ sharedStorageContext=]. - 1. [=Navigate=] |element|'s [=fenced navigable container/fenced navigable=] to |urn uuid| using - |element|'s [=Node/node document=], with [=historyHandling=] set to "`replace`", [=referrerPolicy=] set to "`no-referrer`", and - |shared storage context|. + 1. [=Navigate=] |element|'s [=fenced navigable container/fenced navigable=] to + |navigation url or urn| using |element|'s [=Node/node document=], with [=historyHandling=] set + to "`replace`", [=referrerPolicy=] set to + "`no-referrer`", and |shared storage context|. Note: See [[#navigation-changes]] for the <{fencedframe}>-specific changes to the ordinary navigation flow. @@ -1318,6 +1322,8 @@ maps to an internal [=fenced frame config=] [=struct=]. [Exposed=Window, Serializable] interface FencedFrameConfig { + constructor(USVString url); + readonly attribute FencedFrameConfigSize? containerWidth; readonly attribute FencedFrameConfigSize? containerHeight; readonly attribute FencedFrameConfigSize? contentWidth; @@ -1327,13 +1333,9 @@ maps to an internal [=fenced frame config=] [=struct=]. }; -Note: Note that {{FencedFrameConfig}}s cannot be constructed manually from JavaScript. They can only -be created by config-generating APIs. However, some browsers [support a developer-only -flag](https://github.com/WICG/fenced-frame/issues/94) which help developers test the <{fencedframe}> -element with arbitrary URLs *not* produced by config-generating APIs for development. - Each {{FencedFrameConfig}} has: + * A url, a [=URL=], failure, or null, initially null * A urn, a [=urn uuid=] * A sharedStorageContext, a [=string=] * A containerWidth, a {{FencedFrameConfigSize}} or null @@ -1341,6 +1343,19 @@ Each {{FencedFrameConfig}} has: * A contentWidth, a {{FencedFrameConfigSize}} or null * A contentHeight, a {{FencedFrameConfigSize}} or null +Note: A config's [=fencedframeconfig/url=] is only null if a [=fencedframeconfig/urn=] is supplied. + +
+ The FencedFrameConfig(|url|) constructor method steps + are: + + 1. Let |config| be a [=new=] {{FencedFrameConfig}} object. + + 1. Set |config|'s [=fencedframeconfig/url=] to the result of running the [=URL parser=] on |url|. + + 1. Return |config|. +
+
The {{FencedFrameConfig/containerWidth}} IDL attribute getter steps are to return [=this=]'s [=fencedframeconfig/containerWidth=]. @@ -1372,6 +1387,8 @@ Each {{FencedFrameConfig}} has: 1. If |forStorage| is true, then throw a {{DataCloneError}} {{DOMException}}. + 1. Set |serialized|.\[[Url]] to |value|'s [=fencedframeconfig/url=]. + 1. Set |serialized|.\[[Urn]] to |value|'s [=fencedframeconfig/urn=]. 1. Set |serialized|.\[[SharedStorageContext]] to |value|'s [=fencedframeconfig/ @@ -1396,6 +1413,8 @@ Each {{FencedFrameConfig}} has: Their [=deserialization steps=], given |serialized|, |value|, and targetRealm are: + 1. Initialize |value|'s [=fencedframeconfig/url=] to |serialized|.\[[Url]]. + 1. Initialize |value|'s [=fencedframeconfig/urn=] to |serialized|.\[[Urn]]. 1. Initialize |value|'s [=fencedframeconfig/sharedStorageContext=] to From e67a4f985c8173373be4d50491a1638b13f53845 Mon Sep 17 00:00:00 2001 From: Liam Brady Date: Tue, 21 May 2024 08:06:31 -0400 Subject: [PATCH 09/38] Add definitions for event reporting opt in headers (#159) --- spec.bs | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/spec.bs b/spec.bs index 2501a27e..a9a5132f 100644 --- a/spec.bs +++ b/spec.bs @@ -218,6 +218,7 @@ spec: RFC8941; urlPrefix: https://www.rfc-editor.org/rfc/rfc8941.html text: structured header; url: #section-1 for: structured header text: token; url: name-tokens + text: boolean; url: boolean spec: permissions-policy; urlPrefix: https://w3c.github.io/webappsec-permissions-policy type: dfn text: ASCII-serialized policy directive; url: serialized-policy-directive @@ -2514,6 +2515,25 @@ container/fenced navigable=] will fail, as outlined in [[#navigation-patch]].
+

The +\`Allow-Fenced-Frame-Automatic-Beacons\` HTTP response header

+ +Serving a document resource that gets loaded into a {{Document}} that is not [=same origin=] with +its [=Document/browsing context=]'s [=fenced frame config instance=]'s [=fenced frame config +instance/mapped url=] with the Allow-Fenced-Frame-Automatic-Beacons HTTP response header opts in the +{{Document}} to having automatic beacon events trigger when it performs navigations. This header is +a [=structured header=] whose value must be a [=structured header/boolean=]. + +

The +\`Allow-Cross-Origin-Event-Reporting\` HTTP response header

+ +Serving a document resource that gets loaded into a <{fencedframe}> by a [=fenced frame config +instance=] with the Allow-Cross-Origin-Event-Reporting HTTP +response header opts in the {{Document}}'s cross-origin [=child navigables=] to be able to send +{{Fence/reportEvent()}} beacons. This header is a [=structured header=] whose value must be a +[=structured header/boolean=]. +

COOP, COEP, and cross-origin isolation

Outside of this specification, the \`Cross-Origin-Opener-Policy\` @@ -2801,8 +2821,7 @@ content in the <{fencedframe}> or its embedder, exactly one of two things will h 1. Set |navigationParams|'s [=navigation params/fenced frame config instance=]'s [=fenced frame config/cross-origin reporting allowed=] to the result of running [=header list/get a structured field value=] on |navigationParams|'s [=navigation params/response=]'s - [=response/header list=] given "Allow-Cross-Origin-Event-Reporting" and - "`item`". + [=response/header list=] given [:Allow-Cross-Origin-Event-Reporting:] and "`item`". 1. Set |browsingContext|'s [=browsing context/fenced frame config instance=] to |navigationParams|'s [=navigation params/fenced frame config instance=]. @@ -2811,11 +2830,11 @@ content in the <{fencedframe}> or its embedder, exactly one of two things will h 10. Let |automaticBeaconsAllowed| be the result of running [=header list/get a structured field value=] on |navigationParams|'s [=navigation params/response=]'s [=response/header list=] - given "Allow-Fenced-Frame-Automatic-Beacons" and "`item`". + given [:Allow-Fenced-Frame-Automatic-Beacons:] and "`item`". Further rewrite step 10 (now step 12) to return a new {{Document}} with an additional parameter: : [=Document/automatic beacons allowed=] - :: |automaticBeaconsAllowed| + :: |automaticBeaconsAllowed|. TODO: Call the [=fenced frame config instance/on navigate callback=] at the From cd9d57c5b9a79bc181c3ec4c23ebe1c598bee154 Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Tue, 4 Jun 2024 10:05:13 -0400 Subject: [PATCH 10/38] Fix TODO for calling "on navigate callback" (#162) --- spec.bs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spec.bs b/spec.bs index a9a5132f..5bed5fad 100644 --- a/spec.bs +++ b/spec.bs @@ -2739,6 +2739,8 @@ CORP violation report=] algorithm, as leaving it unfenced may cause a privacy le 1. Set |url| to |config|'s [=fenced frame config/mapped url=]'s [=mapped url/value=]. + 1. Run steps in |config|'s [=fenced frame config/on navigate callback=]. + /fenced-frame/frame-navigation.https.html @@ -2837,9 +2839,6 @@ content in the <{fencedframe}> or its embedder, exactly one of two things will h :: |automaticBeaconsAllowed|. -TODO: Call the [=fenced frame config instance/on navigate callback=] at the -appropriate time. -

Browsing context group swap

When the embedder of a <{fencedframe}> initiates navigations inside the frame, we must perform a From 4966a9e2e897540ae1cdcb1b3efd061c85e4c434 Mon Sep 17 00:00:00 2001 From: Youssef B <131692252+HabibiYou@users.noreply.github.com> Date: Tue, 4 Jun 2024 21:12:55 +0000 Subject: [PATCH 11/38] Spec `adAuctionComponents` (#163) --- spec.bs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/spec.bs b/spec.bs index 5bed5fad..9e899fa7 100644 --- a/spec.bs +++ b/spec.bs @@ -1443,6 +1443,7 @@ typedef (USVString or FencedFrameConfig) UrnOrConfig; partial interface Navigator { Promise<undefined> deprecatedReplaceInURN( UrnOrConfig urnOrConfig, record<USVString, USVString> replacements); + sequence<USVString> adAuctionComponents(unsigned short numAdComponents); }; @@ -1505,6 +1506,38 @@ partial interface Navigator { +
+ + The adAuctionComponents(|numAdComponents|) + + 1. Let |instance| be [=this=]'s [=relevant global object=]'s [=Window/browsing context=]'s + [=browsing context/fenced frame config instance=]. + + 1. If |instance| is null, then throw a {{DOMException}}. + + 1. If [=this=]'s [=relevant settings object=]'s [=environment settings object/origin=] and + |instance|'s [=fenced frame config instance/mapped url=]'s [=url/origin=] are not [=same + origin=], then then throw a {{DOMException}}. + + 1. Let |maxAdComponents| be 40. + + 1. If |numAdComponents| > |maxAdComponents|, then set |numAdComponents| to |maxAdComponents|. + + 1. Let |adComponentsURNs| be an empty [=list=] of [=fencedframeconfig/urn=]s. + + 1. [=map/For each=] |urn| → config of |instance|'s + [=fenced frame config instance/nested configs=]: + + 1. If |numAdComponents| equals 0, then [=iteration/break=]. + + 1. [=list/Append=] |urn| to |adComponentsURNs|. + + 1. Set |numAdComponents| to |numAdComponents| − 1. + + 1. Return |adComponentsURNs|. + +
+

The {{Fence}} interface

Several APIs specific to fenced frames are defined on the {{Fence}} interface. From 09f6c66ed52ed370625e19c767ca71787911ca49 Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Thu, 6 Jun 2024 09:52:57 -0400 Subject: [PATCH 12/38] Spec `deprecatedURNtoURL` (#161) --- spec.bs | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/spec.bs b/spec.bs index 9e899fa7..515ce54e 100644 --- a/spec.bs +++ b/spec.bs @@ -1018,7 +1018,7 @@ A destination event is either a Note: The pending event will be sent asynchronously. - 1. [=Assert=] that |reporting map|[|destination|] is a [=map=] (i.e. that |destination|'s + 1. [=Assert=] that |reporting map|[|destination|] is a [=map=] (i.e., that |destination|'s metadata has been finalized). 1. [=Send a beacon=] with |reporting map|[|destination|] and |event|. @@ -1437,12 +1437,20 @@ the API {{Window/navigator}}.{{Navigator/deprecatedReplaceInURN()}}, which allow macros into the [=fenced frame config/mapped url=] corresponding to a given [=urn uuid=] or {{FencedFrameConfig}}. +Note: To help with ease of adoption, +[until third party cookie deprecation](https://developers.google.com/privacy-sandbox/relevance/protected-audience-api/feature-status#fenced_frames) +we will support the API {{Window/navigator}}.{{Navigator/deprecatedURNtoURL()}}, which returns +the [=fenced frame config/mapped url=] corresponding to a given [=urn uuid=] or +{{FencedFrameConfig}}. +
 typedef (USVString or FencedFrameConfig) UrnOrConfig;
 
 partial interface Navigator {
   Promise<undefined> deprecatedReplaceInURN(
     UrnOrConfig urnOrConfig, record<USVString, USVString> replacements);
+  Promise<USVString> deprecatedURNtoURL(
+    UrnOrConfig urnOrConfig, optional boolean send_reports = false);
   sequence<USVString> adAuctionComponents(unsigned short numAdComponents);
 };
 
@@ -1467,7 +1475,8 @@ partial interface Navigator { 1. Otherwise, set |urn| to |urnOrConfig|'s [=fencedframeconfig/urn=]. - 1. If |urn| is TODO invalid, [=exception/throw=] a {{TypeError}}. + 1. If |urn| is not a valid [=urn uuid=] (i.e., won't pass the ABNF in Section 3 of + [=urn uuid=]), [=exception/throw=] a {{TypeError}}. 1. [=map/For each=] |key| → _ of |replacements|: 1. If |key| does not [=string/start with=] ${ or %%, @@ -1481,7 +1490,7 @@ partial interface Navigator { 1. Run the following steps [=in parallel=]: - 1. Let |mapping| be |global|'s [=associated Document=]'s [=node navigable=]'s + 1. Let |mapping| be |global|'s [=Window/navigable=]'s [=navigable/traversable navigable=]'s [=traversable navigable/fenced frame config mapping=]. 1. Let |config| be the result of [=fenced frame config mapping/finding a config=] in |mapping| @@ -1507,7 +1516,47 @@ partial interface Navigator {
+ The deprecatedURNtoURL(|urnOrConfig|, |send_reports|) method + steps are: + + 1. Let |urn| be null. + + 1. If |urnOrConfig| is a {{USVString}}, set |urn| to |urnOrConfig|. + + 1. Otherwise, set |urn| to |urnOrConfig|'s [=fencedframeconfig/urn=]. + 1. If |urn| is not a valid [=urn uuid=] (i.e., won't pass the ABNF in Section 3 of + [=urn uuid=]), [=exception/throw=] a {{TypeError}}. + + 1. Let |p| be [=a new promise=]. + + 1. Let |global| be [=this=]'s [=relevant global object=]. + + 1. Run the following steps [=in parallel=]: + + 1. Let |mapping| be |global|'s [=Window/navigable=]'s + [=navigable/traversable navigable=]'s [=traversable navigable/fenced frame config mapping=]. + + 1. If |mapping|'s [=fenced frame config mapping/finalized config mapping=][|urn|], does not + [=map/exist=], then [=queue a global task=] on the [=DOM manipulation task source=] + given |global|, to [=resolve=] |p| with {{undefined}}, and abort these steps. + + 1. Let |config| be |mapping|'s [=fenced frame config mapping/finalized config mapping=][|urn|]. + + 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |global|, to + [=resolve=] |p| with |config|'s [=fenced frame config/mapped url=]'s [=mapped url/value=]. + + 1. If |send_reports| is true, then run the steps in |config|'s + [=fenced frame config/on navigate callback=]. + + 1. Return |p|. + + + /fenced-frame/deprecated-config-apis.https.html + +
+ +
The adAuctionComponents(|numAdComponents|) 1. Let |instance| be [=this=]'s [=relevant global object=]'s [=Window/browsing context=]'s @@ -1535,7 +1584,6 @@ partial interface Navigator { 1. Set |numAdComponents| to |numAdComponents| − 1. 1. Return |adComponentsURNs|. -

The {{Fence}} interface

@@ -1685,7 +1733,7 @@ Several APIs specific to fenced frames are defined on the {{Fence}} interface. /fenced-frame/fence-report-event-cross-origin-urn-iframe-no-embedder-opt-in.https.html /fenced-frame/fence-report-event-cross-origin-urn-iframe-no-subframe-opt-in.https.html /fenced-frame/fence-report-event-cross-origin-urn-iframe.https.html - /fenced-frame/fence-report-event-cross-origin.https.html + /fenced-frame/fence-report-event-cross-origin.sub.https.html /fenced-frame/fence-report-event-sub-fencedframe.https.html From ec54e04f3a0e7a454766fee8ebeb6ebffc6678a9 Mon Sep 17 00:00:00 2001 From: Shivani Sharma Date: Thu, 6 Jun 2024 12:40:22 -0400 Subject: [PATCH 13/38] Update use_cases.md for correctness Update use_cases.md for correctness and removing outdated information. --- explainer/use_cases.md | 158 +++++++++++++++++++++-------------------- 1 file changed, 82 insertions(+), 76 deletions(-) diff --git a/explainer/use_cases.md b/explainer/use_cases.md index 2085812c..073c1377 100644 --- a/explainer/use_cases.md +++ b/explainer/use_cases.md @@ -1,111 +1,117 @@ -# Fenced frame use cases +# Fenced Frame Use Cases +## Summary -## **Summary** +This document describes some initial targeted use cases of the ` `element on the Web. For each, we’ll answer the following questions: -This document summarizes the various use cases for [fenced frames](https://github.com/shivanigithub/fenced-frame). Each API that uses fenced frames specifies its behavior by generating appropriate [fenced frame configs](https://github.com/shivanigithub/fenced-frame/blob/master/explainer/fenced_frame_config.md). -## **Characteristics of the different use cases** +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. +2. Why does this use case require fenced frames? +## Common factors across all use cases -* All use cases are similar such that they are isolated from the embedded context via any JS window references, script access, storage access, resizing of the fenced frame, messaging APIs etc. -* Every use case of fenced frame is different in how its privacy guarantees are preserved and would need a separate launch/review process. The first phase and the associated review process of fenced frames will focus only on its use by Protected Audience, sharedStorage, and the default `FencedFrameConfig()` constructor(s). -* Each use case’s source url privacy characteristics are different E.g. the “opaque-ads” use case allows providing a config-bound opaque src by the embedder which contains cross-site data e.g. interest groups, the “read-only” use case has src that is known to the embedder and does not need to be mitigated against link decoration. A future “unpartitioned-storage” use case will need the src to be mitigated against link decoration. -* One of the questions we are trying to answer from an API perspective is how to represent these different use cases of fenced frames. Should they be separate elements, all inheriting the base Fenced Frame element; or should they be the same element where you can set an attribute to load configs generated by different APIs; or a hybrid between these two approaches? In phase 1, for simplicity, we are going with it as an attribute and then if need be and based on TAG/standards discussions, we can pivot to create separate elements. +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 +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. -## **Opaque-ads** +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. -This use case is for rendering ads whose url is opaque to the embedding context. The two consumers of this use case are [Protected Audience](https://github.com/WICG/turtledove/blob/main/FLEDGE.md) and [SharedStorage](https://github.com/pythagoraskitty/shared-storage#simple-example-consistent-ab-experiments-across-sites). +## Rendering Ads via the Protected Audience API +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. -* **Use case: “opaque-ads”** -* **Config:** - * Generated by Protected Audience (`navigator.runAdAuction()`) or SharedStorage (`window.sharedStorage.selectURL`). - * The url mapped by the config can only be an https, localhost, about:blank. - * Note that for this use case, the interesting part is that the source is opaque to the publisher and that is what is discussed in the information flow section below. - -* **Example** usage from Protected Audience: - ```js - navigator.runAdAuction(myAuctionConfig).then((auctionWinnerConfig) => { - // auctionWinnerConfig value e.g. - // FencedFrameConfig { - // src: opaque - // containerWidth: 100, - // containerHeight: 200, - // contentWidth: opaque, - // contentHeight: opaque, - // ... - // } - var adFrame = document.createElement('fencedframe'); - adFrame.config = auctionWinnerConfig; - }); - ``` +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: -* **Information flow and privacy model:** - * Src is always guaranteed to be opaque to the embedding context via the config mechanism described above. - * The API that generates the config will enforce that the URL and any other information passed to the fenced frame are k-anonymous. Resizing of the fenced frame by the embedder will also be restricted in the sense that the document loaded in the fenced frame will be scaled for the new size but will not be able to access the current size. - * The network access being unrestricted is an ongoing technical challenge due to the issue of network timing side channel (described in the explainer [here](https://github.com/WICG/fenced-frame/blob/master/explainer/network_side_channel.md)) and we are considering what a long-term solution for this would look like in fenced frames. For the opaque-ads use case, the considerations are either 1) denying any network access (e.g., loaded via navigable web bundles) or 2) network access only allowed to some trusted caching service that promises to only log aggregate data. - * Like all use cases, the fenced frame is isolated from the embedded context via any JS window references, script access, storage access, messaging APIs etc. The fenced frame does not know the embedding site’s origin or etld+1. - * The fenced frame is allowed to create a popup (with noopener) or navigate the top-level page on user activation as described [here](https://github.com/WICG/fenced-frame/blob/master/explainer/integration_with_web_platform.md#top-level-navigation). (This is an ads requirement) -* **Cross-site data**: Interest groups in Protected Audience, the cross-site data used to choose the one-of-N URLs for shared storage. -* **Reporting**: Reporting for ads would eventually be done using aggregate reporting but for easier adoption there is event-level reporting that will be allowed. Events happening inside the fenced frames will be joined with the data from the Protected Audience/SharedStorage worklet and sent as a beacon. This is detailed [here](https://github.com/WICG/turtledove/blob/main/Fenced_Frames_Ads_Reporting.md) -## **Default** +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()`. +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. -This use case is the fenced frames with no special restrictions on the src and no cross-site data inside the fenced frame. It is useful to test fenced frames and can be used for a scenario where the fenced frame itself does not get any special cross-site data but the use case can benefit from the isolation characteristics of a fenced frame. +Using fenced frames to render the ad creative provides some significant privacy benefit to the end user. -* **Use case: “default”** -* **Config:** Generated by the `FencedFrameConfig(url)` WebIDL constructor. The url must be [Potentially trustworthy](https://w3c.github.io/webappsec-secure-contexts/#potentially-trustworthy-url) url but has no restrictions on its contents -* **Information flow and privacy model:** - * Since there is no unpartitioned/cross-site data available to the fenced frame, it is not able to do any cross-site data joining. - * Like all use cases, the fenced frame is isolated from the embedded context via any JS window references, script access, storage access, messaging APIs etc. The fenced frame does not know the embedding site’s origin or etld+1. -To begin experimenting with fenced frames in default mode, enable the following experiments in `chrome://flags`: -* Privacy Sandbox Ads APIs (chrome://flags/#privacy-sandbox-ads-apis) -* Enable the \`FencedFrameConfig\` constructor. (chrome://flags/#enable-fenced-frames-developer-mode) +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)._ +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). -After relaunching Chrome, a fenced frame can be added to a page with the following code: -``` -const frame = document.createElement("fencedframe"); -const config = new FencedFrameConfig("https://example.com/"); -frame.config = config; -document.body.append(frame); -``` +**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.** -## **Read-only** -This use case is for rendering personalized information in a fenced frame at the same time ensuring that the unpartitioned data accessed by the fenced frame cannot be exfiltrated, by disallowing network and any write access to storage . The two consumers of this use case are [3rd party payment service provider(PSP)'s customized payment buttons](https://github.com/shivanigithub/fenced-frame/issues/15) and possibly a version of [FedCM](https://github.com/fedidcg/FedCM) (the latter is under discussion). +## Selecting and rendering a URL based on cross-site data via SelectURL +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: -* **Use case: “read-only”** -* **Config:** Generated by some API like `ReadOnlyFencedFrameConfig(url)`. url can only be an https, localhost or about:blank. Is able to carry 1p data from the embedding context to the fenced frame. This is not however an issue as described in the next section. -* **Information flow and privacy model:** - * The ‘src’ url can carry user id in the embedding page. Up until the fenced frame has completed navigation, there is an unrestricted network. That is fine because there isn’t any unpartitioned data available to the fenced frame till that point. - * The fenced frame is able to request access to read-only cookies after navigation is complete. At that point the network will be disallowed so that there is no exfiltration of joined data across sites via either the network or persistent storage. Other partitioned state like storage, service workers, network and http cache will continue to stay partitioned. -* **Top-level site’s etld+1**: This is required in the initial navigation request so that the PSP/FedCM servers can determine if this is a trusted top-level site that they are allowed to work with. - * This is fine because it does not exfiltrate any new information that the embedder itself could not have sent to the payment service provider's server. -* **Cross-site data**: Read only access to unpartitioned cookies after navigation is complete (document and subresources have loaded) and network is then restricted. +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. +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. +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. +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. -## **Unpartitioned-storage** +This framework is generic enough that it can fill many niches, but some specific use cases that have been identified for advertising are: -This use case is for authenticated embeds e.g. embedded videos, comments etc. +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. +2. Respecting user display preferences for widgets across sites. -* **Use case: “unpartitioned-storage”** -* **Config:** Generated by some API like `UnpartitionedStorageFencedFrameConfig(url)`. The specified src url should be mitigated against link decoration. (TODO: design) -* **Top-level site’s url**: This may be granted on user activation and permission prompt. (TODO: design) -* **Information flow and privacy model:** - * User id from the embedding site is not allowed because of the source url being mitigated against link decoration. - * The fenced frame gets access to unpartitioned storage + top-level url (also mitigated against link decoration) on user activation and permission prompt. -* **Cross-site data:** Gates unpartitioned storage access on user activation + permission prompt. +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. + +**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.** + + +## Personalizing Document Content with Local Unpartitioned Data Access + +**_[Not launched as of H1 2024]_** + +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 full access to user cross-site data. This would allow for full 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 full cross-site data. + +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. + +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: + + + +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. +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. +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. + +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). + + +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. + + +## Manual Construction for General Purpose Usage and Testing + +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? + +Example scenarios include: + + + +* 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. +* A third-party payments provider currently embeds a personalized button as described above, but personalization only occurs after calling `window.fence.disableUntrustedNetwork()`. +* 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. + +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: + +const frame = document.createElement("fencedframe"); + const config = new FencedFrameConfig("https://example.com/"); + frame.config = config; + document.body.append(frame); + + +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. + +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. + + + +* Privacy Sandbox Ads APIs (`chrome://flags/#privacy-sandbox-ads-apis`) +* Enable the `FencedFrameConfig` constructor (`chrome://flags/#enable-fenced-frames-developer-mode`) From 0df6579ed837e6a7c49b70df53e5682fc960d6e4 Mon Sep 17 00:00:00 2001 From: Shivani Sharma Date: Wed, 10 Jul 2024 14:58:17 -0400 Subject: [PATCH 14/38] security considerations security considerations section updated --- ...fenced_frames_with_local_unpartitioned_data_access.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/explainer/fenced_frames_with_local_unpartitioned_data_access.md b/explainer/fenced_frames_with_local_unpartitioned_data_access.md index 572f5502..9baa316a 100644 --- a/explainer/fenced_frames_with_local_unpartitioned_data_access.md +++ b/explainer/fenced_frames_with_local_unpartitioned_data_access.md @@ -296,7 +296,7 @@ An additional element of user privacy is the ability to control this feature via ## Security considerations -This new variant of fenced frames (constructed with a normal URL instead of an 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). +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). ### Permissions delegation @@ -311,10 +311,13 @@ Fenced frames constructed using the non-opaque URL constructor do not have to wo 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. -### Ongoing technical considerations +### Process Isolation -There are ongoing technical considerations, which we will be updating here once the design is crystallized. Specifically, we would like to revisit the fenced frames [process isolation model](https://github.com/WICG/fenced-frame/blob/master/explainer/process_isolation.md) for this variant. +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. +### CSP:frame-ancestors +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. +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. ## Stakeholder Feedback / Opposition From ab74aeba0e6b4bf71b1bfb4dc5e893693293042c Mon Sep 17 00:00:00 2001 From: Shivani Sharma Date: Wed, 10 Jul 2024 15:23:45 -0400 Subject: [PATCH 15/38] frame-ancestors update frame-ancestors update --- explainer/integration_with_web_platform.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/explainer/integration_with_web_platform.md b/explainer/integration_with_web_platform.md index a570abf9..34cf1db9 100644 --- a/explainer/integration_with_web_platform.md +++ b/explainer/integration_with_web_platform.md @@ -53,7 +53,7 @@ For COEP, If the fenced frame’s embedding page enables COEP then the fenced fr ## Opt-in header 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). -It is also important for sites to opt-in due to security reasons. Due to privacy reasons, a fenced frame does not honor headers like frame-ancestors and x-frame-options all the way up to the primary top-level frame but only till the fenced frame root. +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. ## Fetch metadata integration 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. From 7889258704aac3dc2b32a49f6951ab06aeedccc1 Mon Sep 17 00:00:00 2001 From: Shivani Sharma Date: Fri, 12 Jul 2024 11:23:49 -0400 Subject: [PATCH 16/38] Obsolete opaque_ads_use_cases.md --- explainer/opaque_ads_use_cases.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/explainer/opaque_ads_use_cases.md b/explainer/opaque_ads_use_cases.md index 6c3dd3c1..33f6369d 100644 --- a/explainer/opaque_ads_use_cases.md +++ b/explainer/opaque_ads_use_cases.md @@ -1,3 +1,5 @@ +# Obsolete: This file's contents are obsolete. Instead please look at https://github.com/WICG/fenced-frame/blob/master/explainer/use_cases.md + ## Use-cases/Key scenarios Following are the use cases for fenced frames loading [ads with opaque urls](https://github.com/shivanigithub/fenced-frame/blob/master/explainer/use_cases.md#opaque-ads). From c799ffe9644f2d8d076cfde40989db81acddc8a3 Mon Sep 17 00:00:00 2001 From: Liam Brady Date: Tue, 13 Aug 2024 06:17:42 -0700 Subject: [PATCH 17/38] Spec: fix typo in ad component section (#175) --- spec.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec.bs b/spec.bs index 515ce54e..4a89afcb 100644 --- a/spec.bs +++ b/spec.bs @@ -1156,7 +1156,7 @@ A fenced frame config is a [=struct=] with the following [=str :: A [=boolean=], initially false. - Note: When true, this [=fenced frame config=] reprsents an ad component. An ad component can be + Note: When true, this [=fenced frame config=] represents an ad component. An ad component can be used to construct ads composed of multiple pieces. See the Protected Audience explainer. For an ad component, event reporting is handled differently. See the Date: Sun, 25 Aug 2024 18:31:18 -0400 Subject: [PATCH 18/38] Add WebRTC section to Web Platform integration page. (#184) We've decided to disable WebRTC peer connections in fenced frames, the rationale for which is described in this explainer patch. --- explainer/integration_with_web_platform.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/explainer/integration_with_web_platform.md b/explainer/integration_with_web_platform.md index 34cf1db9..8d2fe75a 100644 --- a/explainer/integration_with_web_platform.md +++ b/explainer/integration_with_web_platform.md @@ -96,6 +96,23 @@ The [MediaDevices interface](https://w3c.github.io/mediacapture-main/#mediadevic 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. +## WebRTC +[WebRTC](https://webrtc.org/) ([spec](https://www.w3.org/TR/webrtc/#intro)) is an open standard and set of APIs with two primary purposes: + +1. Enable media capture of cameras, microphones, and displays. +1. Facilitate peer-to-peer communication between clients for the purpose of sharing captured media or other arbitrary data. + +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. + +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: + +1. Utility: We have not yet identified any use cases for fenced frames that would require WebRTC peer connections. + 1. A significant amount of WebRTC utility is already hampered by the disabled media capture permissions. +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. +1. Complexity: Network revocation for `RTCPeerConnection` would likely be more involved than other types of requests, for potentially little benefit given 1 and 2. + +Navigation, subresource fetches, and Websockets will still be enabled in fenced frames by default, but disabled after a call to `window.fence.disableUntrustedNetwork()`. + ## Chromium implementation: Top-level browsing context using MPArch 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. From 00676a5c95ba4f0984ff8f33b7cf7fd6807c5b6a Mon Sep 17 00:00:00 2001 From: Liam Brady Date: Mon, 26 Aug 2024 14:18:55 -0700 Subject: [PATCH 19/38] Spec sandbox attribute + handling (#180) --- spec.bs | 147 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 124 insertions(+), 23 deletions(-) diff --git a/spec.bs b/spec.bs index 4a89afcb..e0cf0053 100644 --- a/spec.bs +++ b/spec.bs @@ -93,6 +93,8 @@ spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/ text: queue a cross-origin embedder policy inheritance violation; url: queue-a-cross-origin-embedder-policy-inheritance-violation text: determine navigation params policy container; url: determining-navigation-params-policy-container text: cross-origin opener policy enforcement result; url: coop-enforcement-result + text: determine the creation sandboxing flags; url: determining-the-creation-sandboxing-flags + text: iframe sandboxing flag set; url: iframe-sandboxing-flag-set for: cross-origin opener policy enforcement result text: needs a browsing context group switch; url: coop-enforcement-bcg-switch urlPrefix: dom.html @@ -145,6 +147,7 @@ spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/ text: navigable; url: navigation-params-navigable text: origin; url: navigation-params-origin text: COOP enforcement result; url: navigation-params-coop-enforcement-result + text: final sandboxing flag set; url: navigation-params-sandboxing for: history handling behavior text: replace; url: hh-replace for: document state @@ -411,6 +414,7 @@ interface HTMLFencedFrameElement : HTMLElement { [CEReactions] attribute FencedFrameConfig? config; [CEReactions] attribute DOMString width; [CEReactions] attribute DOMString height; + [SameObject, PutForwards=value] readonly attribute DOMTokenList sandbox; [CEReactions] attribute DOMString allow; }; @@ -424,6 +428,22 @@ Descendants of <{fencedframe}> elements represent nothing. Each <{fencedframe}> has a config, which is either a {{FencedFrameConfig}} or null. It is initially null. +Each <{fencedframe}> has a fencedframe sandboxing flag set, which is a +[=sandboxing flag set=]. Which flags in a [=fencedframe/fencedframe sandboxing flag set=] are set +at any particular time is determined by the <{fencedframe}> element's <{fencedframe/sandbox}> +attribute. + +
+ Modify the [=determine the creation sandboxing flags=] algorithm. Rewrite the second step in the + union to be the following 2 steps: + + * If |embedder| is an <{iframe}> element, then: the flags set on |embedder|'s [=iframe sandboxing + flag set=]. + + * If |embedder| is a <{fencedframe}> element, then: the flags set on |embedder|'s [=fencedframe/ + fencedframe sandboxing flag set=]. +
+
When a <{fencedframe}> element |element| is [=node is inserted into a document|inserted into a document=] whose [=Document/browsing context=] is non-null, run these steps: @@ -433,7 +453,8 @@ Each <{fencedframe}> has a config, which is either a 1. Set |nested traversable|'s [=navigable/loading mode=] to "`fencedframe`". - 1. Parse the sandbox attributes, once it exists + 1. If |element| has a <{fencedframe/sandbox}> attribute, then [=parse a sandboxing directive=] + given the attribute's value and |element|'s [=fencedframe/fencedframe sandboxing flag set=]. Issue: It's not necessary to call the URL @@ -492,8 +513,46 @@ The allow attribute, when specified, det in the <{fencedframe}>'s [=fenced navigable container/fenced navigable=] is initialized. Its value must be a [=serialized permissions policy=]. [[!PERMISSIONS-POLICY]] -The IDL attribute allow must [=reflect=] the -respective content attribute of the same name. +The sandbox attribute, when specified, enables a set of +extra restrictions on any content hosted by the <{fencedframe}>. Its value must be an [=unordered +set of unique space-separated tokens=] that are [=ASCII case-insensitive=]. The allowed values are: + +* <{iframe/sandbox/allow-downloads}> +* <{iframe/sandbox/allow-forms}> +* <{iframe/sandbox/allow-modals}> +* <{iframe/sandbox/allow-orientation-lock}> +* <{iframe/sandbox/allow-pointer-lock}> +* <{iframe/sandbox/allow-popups}> +* <{iframe/sandbox/allow-popups-to-escape-sandbox}> +* <{iframe/sandbox/allow-presentation}> +* <{iframe/sandbox/allow-same-origin}> +* <{iframe/sandbox/allow-scripts}> +* <{iframe/sandbox/allow-top-navigation}> +* <{iframe/sandbox/allow-top-navigation-by-user-activation}> +* <{iframe/sandbox/allow-top-navigation-to-custom-protocols}> + +The IDL attributes allow and sandbox must [=reflect=] the respective content attribute of the +same name. + +The supported tokens for {{HTMLFencedFrameElement/sandbox}}'s {{DOMTokenList}} are the allowed +values defined in the <{fencedframe/sandbox}> attribute and supported by the user agent. + +
+The following [=attribute change steps=], given |element|, |localName|, oldValue, +|value|, and |namespace| are used for all <{fencedframe}> elements: + +1. [=Assert=]: |namespace| is the [=HTML namespace=]. + +1. If |localName| is <{fencedframe/sandbox}>, then: + + 1. If |value| is null, then [=set/empty=] |element|'s [=fencedframe/fencedframe sandboxing flag + set=]. + + 1. Otherwise, run [=parse a sandboxing directive=] given the |value| and |element|'s + [=fencedframe/fencedframe sandboxing flag set=]. + +

Dimension attributes

@@ -715,9 +774,6 @@ following [=struct/items=]: :: a [=string=] -An exhaustive set of sandbox flags is a [=sandboxing flag -set=]. - A pending event is a [=struct=] with the following [=struct/items=]: @@ -1094,12 +1150,12 @@ A fenced frame config is a [=struct=] with the following [=str : on navigate callback :: null, or a series of steps - : effective sandbox flags + : effective sandboxing flags :: null, or a [=struct=] with the following [=struct/items=]: - : value - :: an [=fencedframetype/exhaustive set of sandbox flags=] + : value + :: a [=sandboxing flag set=] - : visibility + : visibility :: a [=fencedframeconfig/visibility=] : effective enabled permissions @@ -1183,8 +1239,8 @@ A fenced frame config instance is a [=struct=] with the follow : on navigate callback :: null, or a series of steps - : effective sandbox flags - :: null, or an [=fencedframetype/exhaustive set of sandbox flags=] + : effective sandboxing flags + :: null, or a [=sandboxing flag set=] : effective enabled permissions :: null, or a [=list=] of [=policy-controlled features=] @@ -1233,9 +1289,9 @@ A fenced frame config instance is a [=struct=] with the follow : [=fenced frame config instance/on navigate callback=] :: |config|'s [=fenced frame config/on navigate callback=] - : [=fenced frame config instance/effective sandbox flags=] - :: |config|'s [=fenced frame config/effective sandbox flags=] if null, otherwise |config|'s - [=fenced frame config/effective sandbox flags=]'s [=effective sandbox flags/value=] + : [=fenced frame config instance/effective sandboxing flags=] + :: |config|'s [=fenced frame config/effective sandboxing flags=] if null, otherwise |config|'s + [=fenced frame config/effective sandboxing flags=]'s [=effective sandboxing flags/value=] : [=fenced frame config instance/effective enabled permissions=] :: |config|'s [=fenced frame config/effective enabled permissions=] if null, otherwise @@ -2832,6 +2888,22 @@ CORP violation report=] algorithm, as leaving it unfenced may cause a privacy le navigable=], or the result of [=checking if unloading is user-canceled=] for |navigable|'s [=navigable/active document=]'s [=Document/inclusive descendant navigables=] otherwise. + Add a step after step 22.8.2 (Let |finalSandboxFlags| be the [=set/union=]...) that reads: + + 3. If |sourceSnapshotParams|'s [=source snapshot params/target fenced frame config=] is not null, + and if |sourceSnapshotParams|'s [=source snapshot params/target fenced frame config=]'s + [=fenced frame config/effective sandboxing flags=] is not null, then set |finalSandboxFlags| to + the [=set/union=] of |finalSandboxFlags| and |sourceSnapshotParams|'s [=source snapshot + params/target fenced frame config=]'s [=fenced frame config/effective sandboxing flags=]' + [=effective sandboxing flags/value=]. + + Note: This ensures that the |finalSandboxFlags| are *at least* as restrictive as the [=fenced + frame config/effective sandboxing flags=] defined in the [=source snapshot params/target fenced + frame config=]. A separate check in the [=should navigation response to navigation request be + blocked by sandboxing flags?|blocked by sandboxing flags?=] algorithm will make sure that + |finalSandboxFlags| is not more restrictive than the [=fenced frame config/effective sandboxing + flags=]. + /fenced-frame/before-unload.https.html @@ -3298,16 +3370,18 @@ algorithms to achieve the outcomes described in the above explanatory content.
- Modify [[HTML]]'s [=attempt to populate the history entry's document=] algorithm. Add a step - before the step inside the [=queue a task|queued task=] starting with "If - |failure| is true, then:" that reads: + Modify [[HTML]]'s [=attempt to populate the history entry's document=] algorithm. Add the + following conditions to step 6.4 (Otherwise, if any of the following are true:) that say: + + * The result of [=should navigation response to navigation request be blocked by Permissions + Policy?=] given navigationParams is "`Blocked`"; - 8. Otherwise, if the result of [=should navigation response to navigation request be blocked by - Permissions Policy?=] given navigationParams is "`Blocked`", then set - |failure| to true. + * The result of [=should navigation response to navigation request be blocked by sandboxing + flags?=] given navigationParams and sourceSnapshotParams is + "`Blocked`"; - Note: If this algorithm returns "`Blocked`", the pre-existing {{Document}} in the <{fencedframe}> - does not stick around; an error page will be loaded. + Note: If any of these algorithms returns "`Blocked`", the pre-existing {{Document}} in the + <{fencedframe}> does not stick around; an error page will be loaded.
@@ -3359,6 +3433,33 @@ algorithms to achieve the outcomes described in the above explanatory content. 1. Return "`Allowed`."
+
+ Should navigation response to navigation request be blocked by sandboxing flags? + + Given a [=navigation params=] (|navigationParams|) and a [=source snapshot params=] + (|sourceSnapshotParams|), this algorithm returns "`Blocked`" or "`Allowed`": + + 1. Let |navigable| be |navigationParams|'s [=navigation params/navigable=]. + + 1. If |navigable| is not a [=fenced navigable container/fenced navigable=], then return + "`Allowed`". + + 1. Let |effectiveSandboxingFlags| be the |sourceSnapshotParams|'s [=source snapshot params/target + fenced frame config=]'s [=fenced frame config/effective sandboxing flags=]. + + 1. If |navigationParams|'s [=navigation params/final sandboxing flag set=] is not a [=set/subset=] + of |effectiveSandboxingFlags|, then return "`Blocked`". + + Note: This means that the [=navigation params/final sandboxing flag set=] cannot restrict a + feature that isn't already restricted in the [=fenced frame config instance/effective + sandboxing flags=], as the extra restrictions can be used as a communication channel. By this + point, the [=navigation params/final sandboxing flag set=] will already have been set to + something *at least* as restrictive as the [=fenced frame config instance/effective sandboxing + flags=]. + + 1. Otherwise, return "`Allowed`". +
+
Modify the [$Define an inherited policy for feature in container at origin$] algorithm to read: From 67d2fa4cf68932c39f8c411fb52213779922483b Mon Sep 17 00:00:00 2001 From: Nan Lin <80365263+linnan-github@users.noreply.github.com> Date: Wed, 28 Aug 2024 21:33:07 -0400 Subject: [PATCH 20/38] Set attribution reporting headers even if there's no supported registrar (#177) --- spec.bs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spec.bs b/spec.bs index e0cf0053..44a4bc21 100644 --- a/spec.bs +++ b/spec.bs @@ -938,9 +938,8 @@ A destination event is either a 1. Set |destination url| to |destination map|[|eventType|]. - 1. If |event|'s [=destination enum event/attributionReportingEnabled=] is true and the result - of [=getting supported registrars=] is not [=list/is empty|empty=] and |event|'s - [=destination enum event/attributionReportingContextOrigin=] [=check if an origin is suitable|is suitable=]: + 1. If |event|'s [=destination enum event/attributionReportingEnabled=] is true + and |event|'s [=destination enum event/attributionReportingContextOrigin=] [=check if an origin is suitable|is suitable=]: 1. If |event|'s {{FenceEvent/eventType}} matches one of the [=fencedframetype/automatic beacon event type=] values, set |attributionReportingEligibility| to From 9f5ca7c855e270a145522edac6abe36a0c048ec0 Mon Sep 17 00:00:00 2001 From: Andrew Verge Date: Tue, 3 Sep 2024 09:25:02 -0400 Subject: [PATCH 21/38] Update Click Privacy section with event caching explanation. (#186) * Update Click Privacy section with event caching explanation. This patch explains why cached trusted events cannot be reused by notifyEvent() after the initial dispatch by the browser completes. * Respond to comments --- .../fenced_frames_with_local_unpartitioned_data_access.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/explainer/fenced_frames_with_local_unpartitioned_data_access.md b/explainer/fenced_frames_with_local_unpartitioned_data_access.md index 9baa316a..d1f0d9cb 100644 --- a/explainer/fenced_frames_with_local_unpartitioned_data_access.md +++ b/explainer/fenced_frames_with_local_unpartitioned_data_access.md @@ -198,8 +198,8 @@ The `notifyEvent()` method will not be available in iframes (same-origin or cros Since this is exfiltrating some information (that a click happened) outside the fenced frame, we will need to consider the following privacy considerations: * 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). -* 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/). - +* 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/). +* 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). ## Code Example From a8ec77214d2a190701014227f0bf4f2a22048b5e Mon Sep 17 00:00:00 2001 From: Andrew Verge Date: Wed, 4 Sep 2024 10:51:22 -0400 Subject: [PATCH 22/38] Remove unused config size attributes (#182) * Remove unused config size attributes The IDL containerWidth, containerHeight, contentWidth, and contentHeight attributes not actually implemented in Chromuim, so we should remove them. Additionally, the internal fenced frame config struct does not implement container size, only content size. So we should remove that as well * Remove unused typedefs --- spec.bs | 91 ++------------------------------------------------------- 1 file changed, 3 insertions(+), 88 deletions(-) diff --git a/spec.bs b/spec.bs index 44a4bc21..6bcdd3cb 100644 --- a/spec.bs +++ b/spec.bs @@ -725,9 +725,9 @@ boundary, which can allow for colluding parties to join cross-site data and buil user. To prevent that, the ad auction API [=construct a pending fenced frame config|constructs=] a [=fenced frame config=] whose underlying [=fenced frame config/mapped url|URL=] is opaque to the embedding context. The [=fenced frame config=] is also constructed with restrictions on what the -[=fenced frame config/container size=] and [=fenced frame config/content size=] of the frame must be -and what the [=fenced frame config/effective enabled permissions|permissions policy=] of the frame -must be, as those can be used as fingerprinting vectors. +[=fenced frame config/content size=] of the frame must be and what the [=fenced frame config/ +effective enabled permissions|permissions policy=] of the frame must be, as those can be used as +fingerprinting vectors. Displaying a personalized payment button: @@ -1127,9 +1127,6 @@ A fenced frame config is a [=struct=] with the following [=str : visibility :: a [=fencedframeconfig/visibility=] - : container size - :: null, or a [=fencedframetype/size=] - : content size :: null, or a [=struct=] with the following [=struct/items=]: : value @@ -1226,9 +1223,6 @@ A fenced frame config instance is a [=struct=] with the follow : mapped url :: a [=URL=] - : container size - :: null, or a [=fencedframetype/size=] - : content size :: null, or a [=fencedframetype/size=] @@ -1274,9 +1268,6 @@ A fenced frame config instance is a [=struct=] with the follow : [=fenced frame config instance/mapped url=] :: |config|'s [=fenced frame config/mapped url=]'s [=mapped url/value=] - : [=fenced frame config instance/container size=] - :: |config|'s [=fenced frame config/container size=] - : [=fenced frame config instance/content size=] :: |config|'s [=fenced frame config/content size=] if null, otherwise |config|'s [=fenced frame config/content size=]'s [=content size/value=] @@ -1373,18 +1364,9 @@ maps to an internal [=fenced frame config=] [=struct=].
   enum OpaqueProperty {"opaque"};
 
-  typedef (unsigned long or OpaqueProperty) FencedFrameConfigSize;
-  typedef USVString FencedFrameConfigURL;
-
   [Exposed=Window, Serializable]
   interface FencedFrameConfig {
     constructor(USVString url);
-    
-    readonly attribute FencedFrameConfigSize? containerWidth;
-    readonly attribute FencedFrameConfigSize? containerHeight;
-    readonly attribute FencedFrameConfigSize? contentWidth;
-    readonly attribute FencedFrameConfigSize? contentHeight;
-
     undefined setSharedStorageContext(DOMString contextString);
   };
 
@@ -1394,10 +1376,6 @@ Each {{FencedFrameConfig}} has: * A url, a [=URL=], failure, or null, initially null * A urn, a [=urn uuid=] * A sharedStorageContext, a [=string=] - * A containerWidth, a {{FencedFrameConfigSize}} or null - * A containerHeight, a {{FencedFrameConfigSize}} or null - * A contentWidth, a {{FencedFrameConfigSize}} or null - * A contentHeight, a {{FencedFrameConfigSize}} or null Note: A config's [=fencedframeconfig/url=] is only null if a [=fencedframeconfig/urn=] is supplied. @@ -1412,26 +1390,6 @@ Note: A config's [=fencedframeconfig/url=] is only null if a [=fencedframeconfig 1. Return |config|.
-
- The {{FencedFrameConfig/containerWidth}} IDL attribute getter steps are to return [=this=]'s - [=fencedframeconfig/containerWidth=]. -
- -
- The {{FencedFrameConfig/containerHeight}} IDL attribute getter steps are to return [=this=]'s - [=fencedframeconfig/containerHeight=]. -
- -
- The {{FencedFrameConfig/contentWidth}} IDL attribute getter steps are to return [=this=]'s - [=fencedframeconfig/contentWidth=]. -
- -
- The {{FencedFrameConfig/contentHeight}} IDL attribute getter steps are to return [=this=]'s - [=fencedframeconfig/contentHeight=]. -
-
The setSharedStorageContext(|contextString|) method steps are to set [=this=]'s [=fencedframeconfig/sharedStorageContext=] to |contextString|. @@ -1449,20 +1407,6 @@ Note: A config's [=fencedframeconfig/url=] is only null if a [=fencedframeconfig 1. Set |serialized|.\[[SharedStorageContext]] to |value|'s [=fencedframeconfig/ sharedStorageContext=]. - - 1. Set |serialized|.\[[ContainerWidth]] to |value|'s [=fencedframeconfig/ - containerWidth=]. - - 1. Set |serialized|.\[[ContainerHeight]] to |value|'s [=fencedframeconfig/ - containerHeight=]. - - 1. Set |serialized|.\[[ContentWidth]] to |value|'s [=fencedframeconfig/ - contentWidth=]. - - 1. Set |serialized|.\[[ContentHeight]] to |value|'s [=fencedframeconfig/ - contentHeight=]. - -
@@ -1475,15 +1419,6 @@ Note: A config's [=fencedframeconfig/url=] is only null if a [=fencedframeconfig 1. Initialize |value|'s [=fencedframeconfig/sharedStorageContext=] to |serialized|.\[[SharedStorageContext]]. - - 1. Initialize |value|'s [=fencedframeconfig/containerWidth=] to |serialized|.\[[ContainerWidth]]. - - 1. Initialize |value|'s [=fencedframeconfig/containerHeight=] to - |serialized|.\[[ContainerHeight]]. - - 1. Initialize |value|'s [=fencedframeconfig/contentWidth=] to |serialized|.\[[ContentWidth]]. - - 1. Initialize |value|'s [=fencedframeconfig/contentHeight=] to |serialized|.\[[ContentHeight]].
Note: To help with ease of adoption, @@ -1864,26 +1799,6 @@ Several APIs specific to fenced frames are defined on the {{Fence}} interface. : [=fencedframeconfig/sharedStorageContext=] :: |config|'s [=fenced frame config/embedder shared storage context=] - : [=fencedframeconfig/containerWidth=] - :: null if |config|'s [=fenced frame config/container size=] is null, otherwise |config|'s - [=fenced frame config/container size=]'s [=size/width=] - - : [=fencedframeconfig/containerHeight=] - :: null if |config|'s [=fenced frame config/container size=] is null, otherwise |config|'s - [=fenced frame config/container size=]'s [=size/height=] - - : [=fencedframeconfig/contentWidth=] - :: null if |config|'s [=fenced frame config/content size=] is null, the `"opaque"` - {{OpaqueProperty}} if |config|'s [=fenced frame config/content size=]'s [=content - size/visibility=] is [=visibility/opaque=], otherwise |config|'s [=fenced frame - config/content size=]'s [=size/width=] - - : [=fencedframeconfig/contentHeight=] - :: null if |config|'s [=fenced frame config/content size=] is null, the `"opaque"` - {{OpaqueProperty}} if |config|'s [=fenced frame config/content size=]'s [=content - size/visibility=] is [=visibility/opaque=], otherwise |config|'s [=fenced frame - config/content size=]'s [=size/height=] - 1. [=list/Append=] |newConfig| to |results|. 1. Return |results|. From ecf159c3c16769e61212705e8e019b63da0342fd Mon Sep 17 00:00:00 2001 From: Andrew Verge Date: Thu, 5 Sep 2024 14:49:34 -0400 Subject: [PATCH 23/38] Re-add fenced frame config internal container size. (#187) Follow-up to https://github.com/WICG/fenced-frame/pull/182 Along with the unused IDL size attributes, I also removed the internal fenced frame config container size definition. I was mistaken about it being vestigial (I missed a reference to it in the implementation when I was originally deciding to remove it, so I didn't see it was actively used). The Protected Audience spec depended on the field, and I broke their build: https://github.com/WICG/turtledove/pull/1270#issuecomment-2332092944 This change re-adds the container size definition to un-break things. --- spec.bs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/spec.bs b/spec.bs index 6bcdd3cb..e548854c 100644 --- a/spec.bs +++ b/spec.bs @@ -725,9 +725,9 @@ boundary, which can allow for colluding parties to join cross-site data and buil user. To prevent that, the ad auction API [=construct a pending fenced frame config|constructs=] a [=fenced frame config=] whose underlying [=fenced frame config/mapped url|URL=] is opaque to the embedding context. The [=fenced frame config=] is also constructed with restrictions on what the -[=fenced frame config/content size=] of the frame must be and what the [=fenced frame config/ -effective enabled permissions|permissions policy=] of the frame must be, as those can be used as -fingerprinting vectors. +[=fenced frame config/container size=] and [=fenced frame config/content size=] of the frame must +be and what the [=fenced frame config/effective enabled permissions|permissions policy=] of the +frame must be, as those can be used as fingerprinting vectors. Displaying a personalized payment button: @@ -1127,6 +1127,9 @@ A fenced frame config is a [=struct=] with the following [=str : visibility :: a [=fencedframeconfig/visibility=] + : container size + :: null, or a [=fencedframetype/size=] + : content size :: null, or a [=struct=] with the following [=struct/items=]: : value @@ -1223,6 +1226,9 @@ A fenced frame config instance is a [=struct=] with the follow : mapped url :: a [=URL=] + : container size + :: null, or a [=fencedframetype/size=] + : content size :: null, or a [=fencedframetype/size=] @@ -1268,6 +1274,9 @@ A fenced frame config instance is a [=struct=] with the follow : [=fenced frame config instance/mapped url=] :: |config|'s [=fenced frame config/mapped url=]'s [=mapped url/value=] + : [=fenced frame config instance/container size=] + :: |config|'s [=fenced frame config/container size=] + : [=fenced frame config instance/content size=] :: |config|'s [=fenced frame config/content size=] if null, otherwise |config|'s [=fenced frame config/content size=]'s [=content size/value=] From 916f93cd80878e6663824d1858afb8acd7241009 Mon Sep 17 00:00:00 2001 From: Nan Lin <80365263+linnan-github@users.noreply.github.com> Date: Thu, 5 Sep 2024 18:29:33 -0400 Subject: [PATCH 24/38] Udpate spec for processing attribution eligible response (#150) --- spec.bs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec.bs b/spec.bs index e548854c..9dd67955 100644 --- a/spec.bs +++ b/spec.bs @@ -948,9 +948,9 @@ A destination event is either a 1. Otherwise, set |attributionReportingEligibility| to "[=eligibility/event-source=]". 1. Set |processResponse| to these steps given a [=response=] |response|: - + 1. Let |fenced| be true. 1. Run [=process an attribution eligible response=] with |event|'s - [=destination enum event/attributionReportingContextOrigin=], |attributionReportingEligibility|, and |response|. + [=destination enum event/attributionReportingContextOrigin=], |attributionReportingEligibility|, |fenced|, and |response|. 1. Set |useParallelQueue| to true. From c10d8f67cab3e08c85e271a926d8d5d6986bcc07 Mon Sep 17 00:00:00 2001 From: Liam Brady Date: Wed, 11 Sep 2024 10:23:25 -0700 Subject: [PATCH 25/38] Spec: fix 'src' permissions policy allowlist. (#172) --- spec.bs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/spec.bs b/spec.bs index 9dd67955..9fcd3e62 100644 --- a/spec.bs +++ b/spec.bs @@ -230,6 +230,7 @@ spec: permissions-policy; urlPrefix: https://w3c.github.io/webappsec-permissions text: the special value *; url: the-special-value text: permissions policy; url: permissions-policy text: policy directive; url: policy-directive + text: declared origin; url: declared-origin for: permissions policy text: declared policy; url: permissions-policy-declared-policy text: inherited policy; url: permissions-policy-inherited-policy @@ -3433,7 +3434,21 @@ algorithms to achieve the outcomes described in the above explanatory content. and |origin| is [=same origin=] with |document|'s origin, return "Enabled". +
+Modify the [=declared origin=] algorithm. Add a new step after step 3 that reads: + +4. If |node|'s [=Node/node document=]'s [=Document/browsing context=]'s [=browsing context/fenced + frame config instance=] is not null, then return |node|'s [=Node/node document=]'s + [=Document/browsing context=]'s [=browsing context/fenced frame config instance=]'s [=fenced + frame config instance/mapped url=]. + +Note: This ensures that the `'src'` [=allowlist=] that can be set in the <{fencedframe/allow}> +attribute works when using a [=fenced frame config=] to navigate a <{fencedframe}> (or a urn that +maps to a [=fenced frame config=] to navigate an <{iframe}>). +
+ + /fenced-frame/allow-attribute-src.https.html /fenced-frame/default-enabled-features-allow-all.https.html /fenced-frame/default-enabled-features-allow-none.https.html /fenced-frame/default-enabled-features-allow-self.https.html From ef0bd15e6c6030973ab090a59eab2d43b9ab2d5f Mon Sep 17 00:00:00 2001 From: Dominic Farolino Date: Thu, 12 Sep 2024 10:12:32 -0400 Subject: [PATCH 26/38] Export `fenced navigable` (#190) --- spec.bs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec.bs b/spec.bs index 9fcd3e62..2149413a 100644 --- a/spec.bs +++ b/spec.bs @@ -2203,9 +2203,9 @@ Similar to [=navigable containers=] and their respective [=navigable container/c other elements (so far, only the <{fencedframe}> element) present a more isolated [=navigable=] to the user. These elements are called fenced navigable containers. -A [=fenced navigable container=] has a fenced navigable, -which is either a [=traversable navigable=] with a non-null [=traversable navigable/unfenced -parent=], or null. It is initially null. +A [=fenced navigable container=] has a fenced +navigable, which is either a [=traversable navigable=] with a non-null [=traversable +navigable/unfenced parent=], or null. It is initially null. /fenced-frame/window-frameElement.https.html From 73d37f8b2b2fbbbdbca5a43b4ee978ee2576a3c8 Mon Sep 17 00:00:00 2001 From: Shivani Sharma Date: Fri, 13 Sep 2024 13:37:00 -0400 Subject: [PATCH 27/38] typo --- explainer/fenced_frames_with_local_unpartitioned_data_access.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/explainer/fenced_frames_with_local_unpartitioned_data_access.md b/explainer/fenced_frames_with_local_unpartitioned_data_access.md index d1f0d9cb..20cd46e1 100644 --- a/explainer/fenced_frames_with_local_unpartitioned_data_access.md +++ b/explainer/fenced_frames_with_local_unpartitioned_data_access.md @@ -77,7 +77,7 @@ Let’s first go through the requirements on the data, taking the example of exa * **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. * **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. -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**. +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**. Some of the enhancements needed for shared storage to be used for this proposal are: From 1454a61b8d4783168b3f3a255570515c2fcca9ca Mon Sep 17 00:00:00 2001 From: Liam Brady Date: Tue, 1 Oct 2024 20:18:27 -0400 Subject: [PATCH 28/38] Spec "Referer" and "Origin" headers in reporting beacons. (#164) --- spec.bs | 182 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 152 insertions(+), 30 deletions(-) diff --git a/spec.bs b/spec.bs index 2149413a..dd51e1e1 100644 --- a/spec.bs +++ b/spec.bs @@ -784,12 +784,21 @@ A pending event is a [=struct=] with the f : event :: a [=fencedframetype/destination event=] + + : request initiator + :: an [=origin=] + + : initiator referrer policy + :: a [=referrer policy=] A reporting destination info is a [=struct=] with the following [=struct/items=]:
+ : reporting url declarer origin + :: an [=origin=] + : reporting url map :: a [=map=] whose [=map/keys=] are [=strings=] and whose [=map/values=] are [=URLs=] @@ -818,10 +827,11 @@ be sent.
In order to finalize a reporting destination, given a [=fencedframetype/fenced - frame reporting map=] |reporting map|, a {{FenceReportingDestination}} |destination|, a [=map=] - |destination map| whose [=map/keys=] are [=strings=] and whose [=map/values=] are [=urls=], and - |macro map|, which is either null or a [=map=] whose [=map/keys=] are [=strings=] and whose - [=map/values=] are [=strings=], run these steps: + frame reporting map=] |reporting map|, a {{FenceReportingDestination}} |destination|, an + [=origin=] |reporting url declarer origin|, a [=map=] |destination map| whose [=map/keys=] are + [=strings=] and whose [=map/values=] are [=urls=], and |macro map|, which is either null or a + [=map=] whose [=map/keys=] are [=strings=] and whose [=map/values=] are [=strings=], run these + steps: 1. [=Assert=] that |reporting map|[|destination|] is a [=list=] (i.e., that |destination|'s metadata has not yet been finalized). @@ -829,6 +839,9 @@ be sent. 1. Let |pending event list| be |reporting map|[|destination|]. 1. [=map/Set=] |reporting map|[|destination|] to a [=struct=] with the following [=struct/items=]: + : [=reporting destination info/reporting url declarer origin=] + :: |reporting url declarer origin| + : [=reporting destination info/reporting url map=] :: |destination map| @@ -837,7 +850,9 @@ be sent. 1. [=list/For each=] |pending event| of |pending event list|: - 1. [=Send a beacon=] with |destination map| and |pending event|'s [=pending event/event=]. + 1. [=Send a beacon=] with |destination map|, |pending event|'s [=pending event/event=], + |pending event|'s [=pending event/request initiator=], and |pending event|'s [=pending + event/initiator referrer policy=].
A fenced frame reporting metadata is a [=struct=] with the @@ -916,7 +931,8 @@ A destination event is either a
In order to send a beacon with a [=fencedframetype/reporting destination info=] - |destination info| and a [=fencedframetype/destination event=] |event|, run these steps: + |destination info|, a [=fencedframetype/destination event=] |event|, an [=origin=] + |request initiator|, and a [=referrer policy=] |initiator referrer policy| run these steps: 1. Let |destination url| be an empty [=string=]. @@ -1003,11 +1019,21 @@ A destination event is either a beacons](https://wicg.github.io/attribution-reporting-api/#ref-for-request-service-workers-mode). : [=request/origin=] - :: Get the origin from somewhere, like the [implementation - does](https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:content/browser/fenced_frame/fenced_frame_reporter.cc;l=384;drc=183dd920ea5d6aed92e007c40e226f1f840c0567). + :: |request initiator| if |event| is a [=fencedframetype/destination URL event=], and + |destination info|'s [=reporting destination info/reporting url declarer origin=] otherwise. + + Note: The reporting destination for a [=fencedframetype/destination URL event=] is determined + by the {{Document}} that calls {{Fence/reportEvent()}}, as opposed to a [=fencedframetype/ + destination enum event=] or [=fencedframetype/automatic beacon event=] whose reporting + destinations are determined in the worklet that created the [=fenced frame config=] that + loaded this {{Document}}. We set the [=request/origin=] to the [=origin=] of the {{Document}} + or worklet that determined the reporting destination to prevent cross-site request forgery. : [=request/referrer=] - :: `"no-referrer"` + :: |request initiator| + + : [=request/referrer policy=] + :: |initiator referrer policy| : [=request/mode=] :: `"cors"` @@ -1030,8 +1056,9 @@ A destination event is either a
In order to report an event using a [=fencedframetype/fenced frame reporter=] - |reporter| with a {{FenceReportingDestination}} |destination|, and a - [=fencedframetype/destination event=] |event|, run these steps: + |reporter| with a {{FenceReportingDestination}} |destination|, an [=origin=] |request initiator|, + a [=referrer policy=] |initiator referrer policy|, and a [=fencedframetype/destination event=] + |event|, run these steps: 1. Let |metadata| be |reporter|'s [=fenced frame reporter/fenced frame reporting metadata reference=]. @@ -1068,6 +1095,12 @@ A destination event is either a : [=pending event/event=] :: |event| + : [=pending event/request initiator=] + :: |request initiator| + + : [=pending event/initiator referrer policy=] + :: |initiator referrer policy| + 1. [=list/Append=] |newEvent| to |reporting map|[|destination|]. 1. Return. @@ -1077,7 +1110,8 @@ A destination event is either a 1. [=Assert=] that |reporting map|[|destination|] is a [=map=] (i.e., that |destination|'s metadata has been finalized). - 1. [=Send a beacon=] with |reporting map|[|destination|] and |event|. + 1. [=Send a beacon=] with |reporting map|[|destination|], |event|, |request initiator|, and + |initiator referrer policy|.
@@ -1648,6 +1682,14 @@ Several APIs specific to fenced frames are defined on the {{Fence}} interface. 1. If |instance|'s [=fenced frame config instance/fenced frame reporter=] is null, then return. + 1. Let |document| be [=this=]'s [=relevant global object=]'s [=associated Document=]. + + 1. Let |request initiator| be [=this=]'s [=relevant settings object=]'s [=environment settings + object/origin=]. + + 1. Let |initiator referrer policy| be |document|'s [=Document/policy container=]'s [=policy + container/referrer policy=]. + 1. If |event| is a {{DOMString}}: 1. If [=this=]'s [=relevant settings object=]'s [=environment settings object/origin=] and @@ -1686,8 +1728,8 @@ Several APIs specific to fenced frames are defined on the {{Fence}} interface. * |destinationURL| [=url/scheme=] is not "`https`"; 1. Run [=report an event=] using |instance|'s [=fenced frame config instance/fenced frame - reporter=] with {{FenceReportingDestination/buyer}} and a - [=fencedframetype/destination URL event=] that is |event|'s + reporter=] with {{FenceReportingDestination/buyer}}, |request initiator|, |initiator + referrer policy| and a [=fencedframetype/destination URL event=] that is |event|'s {{FenceEvent/destinationURL}}. 1. Otherwise: @@ -1696,8 +1738,6 @@ Several APIs specific to fenced frames are defined on the {{Fence}} interface. 1. [=exception/Throw=] a {{TypeError}}. - 1. Let |document| be [=this=]'s [=relevant global object=]'s [=associated Document=]. - 1. Let |attributionReportingEnabled| be the result of determining whether |document| is [=allowed to use=] the "{{PermissionPolicy/attribution-reporting}}" feature. @@ -1706,8 +1746,8 @@ Several APIs specific to fenced frames are defined on the {{Fence}} interface. 1. [=list/For each=] |destination| of |event|'s {{FenceEvent/destination}}: 1. Run [=report an event=] using |instance|'s [=fenced frame config instance/fenced frame - reporter=] with |destination| and a [=fencedframetype/destination enum event=] with the - following [=struct/items=]: + reporter=] with |destination|, |request initiator|, |initiator referrer policy|, and a + [=fencedframetype/destination enum event=] with the following [=struct/items=]: : [=destination enum event/type=] :: |event|'s {{FenceEvent/eventType}} @@ -1886,6 +1926,15 @@ event|event-level beacon=] when a fenced frame initiates a successful [=navigate cases where a [=navigate|navigation=] to a [=top-level traversable=] does not originate from a <{fencedframe}>. + 1. Let |request initiator| be |sourceOrigin| if |config|'s [=fenced frame config instance/is ad + component=] is false, and |sourceSnapshotParams|'s [=source snapshot params/initiator ancestor + root origin=] otherwise. + + 1. Let |initiator referrer policy| be |sourceSnapshotParams|'s [=source snapshot params/source + policy container=]'s [=policy container/referrer policy=] if |config|'s [=fenced frame config + instance/is ad component=] is false, and |sourceSnapshotParams|'s [=source snapshot + params/initiator ancestor root referrer policy=] otherwise. + 1. Let |beacon data| be |sourceSnapshotParams|'s [=source snapshot params/automatic beacon data map=][|eventType|]. @@ -1908,8 +1957,8 @@ event|event-level beacon=] when a fenced frame initiates a successful [=navigate [=fencedframetype/fenced frame reporting map=]'s [=map/keys=]: 1. Run [=report an event=] using |config|'s [=fenced frame config instance/fenced frame - reporter=] with |destination| and an [=fencedframetype/automatic beacon event=] with the - following [=struct/items=]: + reporter=] with |destination|, |request initiator|, |initiator referrer policy|, and an + [=fencedframetype/automatic beacon event=] with the following [=struct/items=]: : [=automatic beacon event/type=] :: |eventType| @@ -2285,8 +2334,6 @@ To mend the intended distinction between [=top-level traversables=] and [=fenced [=traversable navigable/unfenced parent=] are both null.
-
-
To get the top-level traversable of a [=navigable=] |inputNavigable|: @@ -2664,9 +2711,28 @@ CORP violation report=] algorithm, as leaving it unfenced may cause a privacy le : initiator fenced frame config instance :: a [=fenced frame config instance=] or null, initially null. + : initiator ancestor root origin + :: an [=origin=] or null, initially null. + + : initiator ancestor root referrer policy + :: an [=referrer policy=] or null, initially null. + : target fenced frame config :: a [=fenced frame config=] or null, initially null. + Note: The [=source snapshot params/initiator fenced frame config instance=] is the [=fenced frame + config instance=] that's loaded into a navigation initiator's [=browsing context=], if any exists. + The [=source snapshot params/initiator ancestor root origin=], for component ads, is the origin of + the top-level ad container, if any exists. The [=source snapshot params/initiator ancestor root + referrer policy=], for component ads, is the referrer policy of the top-level ad container, if any + exists. They are used by the [=attempt to send an automatic beacon=] algorithm to compare + [=origin=]s and determine which {{FenceReportingDestination}}s to send beacons and with what + information, if the <{fencedframe}>-initiated navigation succeeds. The [=source snapshot + params/target fenced frame config=] on the other hand, is the non-[=instantiate a + config|instantiated=] [=fenced frame config=] that will be loaded into a <{fencedframe}> element + for navigations targeting fenced frames. These fields do not interact *together* in any meaningful + way. + : attribution reporting enabled :: a [=boolean=]. @@ -2680,14 +2746,6 @@ CORP violation report=] algorithm, as leaving it unfenced may cause a privacy le :: a [=map=] whose [=map/keys=] are [=fencedframetype/automatic beacon event type=]s and whose [=map/values=] are null or an [=fencedframetype/automatic beacon data=] - Note: The [=source snapshot params/initiator fenced frame config instance=] is the [=fenced frame - config instance=] that's loaded into a navigation initiator's [=browsing context=], if any exists. - It is used by the [=attempt to send an automatic beacon=] algorithm to compare [=origin=]s and - determine which {{FenceReportingDestination}}s to send beacons to, if the - <{fencedframe}>-initiated navigation succeeds. The [=source snapshot params/target fenced frame - config=] on the other hand, is the non-[=instantiate a config|instantiated=] [=fenced frame - config=] that will be loaded into a <{fencedframe}> element for navigations targeting fenced - frames. These fields do not interact *together* in any meaningful way.
@@ -2721,6 +2779,57 @@ CORP violation report=] algorithm, as leaving it unfenced may cause a privacy le [=automatic beacon data/once=] set to true.
+
+ To get the initiator's fenced grand-ancestor's navigable of a given {{Document}} + |sourceDocument|: + + 1. Let |navigable| be |sourceDocument|'s [=node navigable=]. + + 1. While |navigable| is not null and |navigable| is not a [=fenced navigable container/fenced + navigable=]: + + 1. Set |navigable| to |navigable|'s [=navigable/parent=]. + + 1. If |navigable| is null, return null. + + 1. [=Assert=]: |navigable| is a [=fenced navigable container/fenced navigable=]. + + 1. Set |navigable| to |navigable|'s [=navigable/unfenced parent=]. + + 1. While |navigable| is not null and |navigable| is not a [=fenced navigable container/fenced + navigable=]: + + 1. Set |navigable| to |navigable|'s [=navigable/parent=]. + + 1. Return |navigable|. + +
+ Given a {{Document}} embedded inside of a <{fencedframe}>, this algorithm gets the navigable of + the document's nearest fenced frame ancestor's nearest fenced frame ancestor. If no such "fenced + frame grand-ancestor" exists, the algorithm returns null. Therefore, this algorithm only returns + a navigable when given a Document that is, at a minimum, in a fenced frame which is itself in a + fenced frame. For example, for the given frame tree structure: + + ``` + Main frame (origin A) + (origin B) +