From a8ac03d8fcb2996a3c105f3e5f7f0308862fd95f Mon Sep 17 00:00:00 2001 From: Liam Brady Date: Thu, 23 May 2024 08:46:21 -0700 Subject: [PATCH] Fenced frames: allow CSP to check ancestors for frame-ancestors. To prevent information from flowing from an embedder into a fenced frame, we have previously disabled checking ancestors of fenced frame roots for the CSP frame-ancestors policy. There is now a need to allow the frame-ancestors policy to look beyond the fenced frame root so that embedders can control what is embedded in its page. `window.fence.notifyEvent()` can be used to send information from a fenced frame with unpartitioned data access to its embedder. Since 1 bit is sent every click, a malicious embedder can exploit this and trick the user into clicking a fenced frame in a certain way that leaks that unpartitioned data. The fenced frame can protect against this with the `frame-ancestors` CSP, only allowing itself to be embedded in certain origins. For this to work, the fenced frame needs to look beyond the fenced frame boundary when calculating if it can load. Since this results in a data inflow channel, this will only be allowed for fenced frames created from the web platform or from Shared Storage, as those are the use cases where data can flow into the fenced frame. Protected Audience-created fenced frames will not have this capability, and will continue to not check beyond the fenced frame root when calculating frame-ancestors. This CL adds a new field to the fenced frame config/properties that notes what API created the fenced frame. This is used in the |AncestorThrottle| class to determine if/how to get the frame's direct ancestor. Change-Id: If7b335700319bad79ef3baf26a6d3f376ae22bc2 Bug: 341356673 --- fenced-frame/ancestor-throttle.https.html | 11 +++--- fenced-frame/csp-ancestors.https.sub.html | 43 +++++++++++++++++++++++ 2 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 fenced-frame/csp-ancestors.https.sub.html diff --git a/fenced-frame/ancestor-throttle.https.html b/fenced-frame/ancestor-throttle.https.html index 9b6dfb0d3051e3..56b1320135a5c4 100644 --- a/fenced-frame/ancestor-throttle.https.html +++ b/fenced-frame/ancestor-throttle.https.html @@ -17,21 +17,24 @@ // Generate the url for the top level fenced frame, including the information // needed to pass on to its nested iframe - const cross_origin = get_host_info().HTTPS_REMOTE_ORIGIN; + const origin = get_host_info().HTTPS_REMOTE_ORIGIN; let fenced_frame_url = generateURL( "resources/ancestor-throttle-inner.https.html", - [ancestor_key, embed_url, cross_origin_to_top_level_iframe]); + [ancestor_key, embed_url, cross_origin_to_top_level_iframe], true); if (cross_origin_to_top_level_fenced_frame) fenced_frame_url = getRemoteOriginURL(fenced_frame_url, true); - attachFencedFrame(fenced_frame_url); + const fenced_frame_config = await generateURNFromFledgeRawURL( + fenced_frame_url, [], true); + + attachFencedFrame(fenced_frame_config); // There is no API to observe whether the document in the FencedFrame loaded // or not. Instead, set up a timeout. If the document loads, "loaded" will be // sent to the server. Otherwise "blocked" will be sent after 3 seconds. step_timeout(() => { writeValueToServer(ancestor_key, "blocked"); - }, 3000); + }, 1000); // Get the result for the fenced frame's nested iframe. const fenced_frame_result = await nextValueFromServer(ancestor_key); diff --git a/fenced-frame/csp-ancestors.https.sub.html b/fenced-frame/csp-ancestors.https.sub.html new file mode 100644 index 00000000000000..da6c73b9dbecab --- /dev/null +++ b/fenced-frame/csp-ancestors.https.sub.html @@ -0,0 +1,43 @@ + +Test Content-Security-Policy frame-ancestors + + + + + + + + +