[go: nahoru, domu]

tree: ca404aaa538f826d4d0e03982c3764b7a35165b3 [path history] [tgz]
  1. automatic_beacon_info.cc
  2. automatic_beacon_info.h
  3. fenced_document_data.cc
  4. fenced_document_data.h
  5. fenced_frame.cc
  6. fenced_frame.h
  7. fenced_frame_browsertest.cc
  8. fenced_frame_config.cc
  9. fenced_frame_config.h
  10. fenced_frame_reporter.cc
  11. fenced_frame_reporter.h
  12. fenced_frame_reporter_unittest.cc
  13. fenced_frame_unittest.cc
  14. fenced_frame_url_mapping.cc
  15. fenced_frame_url_mapping.h
  16. fenced_frame_url_mapping_unittest.cc
  17. OWNERS
  18. README.md
  19. redacted_fenced_frame_config_mojom_traits_unittest.cc
content/browser/fenced_frame/README.md

Fenced Frame: Guidelines for Feature Behavior

Fenced frames are a new HTML element that allows a page to be embedded in another page while preventing any information from being exchanged between the two pages. To maintain this “fence” between a fenced frame and its embedder, any new features need to consider how they should behave inside a fenced frame. Specifically, should they treat the fenced frame as the top-most frame? Or should the feature be allowed to traverse past the fenced frame to get information about its embedder?

Decision chart

The decision chart below is a basic guide to determine how a fenced frame should behave when using a feature:

drawing

Below are more details for each node:

Does this feature need to access the outer frame tree to work properly?

Some features need to interact with either a frame’s immediate ancestor, the nearest main frame in the frame tree, or the outermost main frame in the frame tree.

  • User activation needs to have access to a frame’s ancestors (and their ancestors) to give all of them user activation. However, the feature will not break if it can’t cross the fenced frame boundary to a frame in the outer frame tree.
  • window.top needs to get access to the nearest main frame in the frame tree (the top-most frame as far as the context is concerned). Even though the behavior will be different than if it were to get the outermost main frame, it does not fundamentally break the functionality of this feature.
  • Accessibility trees use the outermost main frame as the root to build the entire accessibility tree from. If a frame in a fenced frame tree doesn’t have access to the outermost main frame, then the accessibility tree won’t be built properly and accessibility functionality will break.

If your feature only needs the immediate ancestor or the nearest main frame, then fenced frames should act as a main frame with your feature..

If you determine that your feature needs a fenced frame to access the outer frame tree (i.e. act as an iframe), you must ensure that no information can leak across the fenced boundary. If any information can leak across the boundary, the feature must be disabled. If the feature cannot be completely disabled, a new approach might need to be formulated (e.g. the ongoing work regarding intersection observer API).

Will it be possible for the web platform to access this information?

As a direct result of your feature, would you be able to write some JavaScript code whose output changes based on the information your feature knows about ancestors in the embedder frame tree? If you decide that your feature needs to give a fenced frame access to information about its ancestors, this next check is very important. You should ensure that the information gathered from an outer frame tree does not end up in a place where it can be observed on the web platform (i.e. through JavaScript). If it is possible for information to cross the fenced frame boundary in a web-observable way, and there’s no way to patch it, the feature must be disabled in fenced frames.

If you can guarantee that your information is k-anonymized through something like FLEDGE, or scrubbed via something like link decoration mitigation, even though information is flowing across the fenced frame boundary, it might be anonymized enough to allow the feature.

Act as main frame.

Unless the feature needs access to something outside of a fenced frame, this is how fenced frames will most likely act with your feature. This means that the feature will think that the fenced frame root is the root of the entire frame tree. This also means that accidentally leaking data across the fenced frame boundary is a lot less likely.

This is accomplished by calling helper functions like RenderFrameHostImpl::GetParent() and RenderFrameHostImpl::GetMainFrame().

  • In RenderFrameHostImpl::SetWindowRect, there’s a check to make sure the call came from the outermost document. Because fenced frames are meant to create a boundary and be their own root frame, having the fenced frame act as a main frame is the correct behavior here. It does not need to know that there is another frame above it, since it should be acting as if it were its own separate tab.
  • The window.top JavaScript call, if it could reach beyond the fenced frame root, could allow the fenced frame to learn about its embedder. Having window.top stop at the fenced frame root will not completely break the feature, since it will just be acting as if the fenced frame were its own separate tab. Because of that, the fenced frame should act as the main frame for this call.
    • The same logic applies for other calls like window.parent, window.postMessage, and history.length.

Act as iframe.

This feature will be made aware of frames above the fenced frame root, and know that there is an outermost root that is not within the fenced frame tree. This path requires extra care, since it becomes possible to have a corner case accidentally leak data across the fenced frame boundary.

This is accomplished by calling helper functions like RenderFrameHostImpl::GetParentOrOuterDocument() and RenderFrameHostImpl::GetOutermostMainFrame().

  • The accessibility tree feature assumes that there is one root frame that everything else branches off of. This is needed to build the accessibility tree, which must have only one root and be able to see everything. That information is exposed to screen readers and other accessibility features, but is never given directly to the web platform. In this case, it is okay for the fenced frame to act as an iframe.
  • When passing focus between frames after the user tab-focuses (switches focus by hitting the tab key), a child fenced frame needs to know what its parent is in order to pass focus off to it. If it’s not allowed to know, it will only be able to pass focus to child frames. The web platform never learns who sent focus to it. That information stays solely in the browser, and all the web platform learns is that it now has focus. Because of that, it is okay for the fenced frame to act as an iframe.
  • Prerendering uses the root frame tree node’s ID as the key to find the pre-rendered page. If it attempted to pass in the ID of the fenced frame node instead, it would not be able to find the pre-rendered page. In this case, the fenced frame would need to act as an iframe.
  • Extensions are a special case. By default, they have access to everything in every tab. For ad blocking extensions specifically, they need to be able to see inside of a fenced frame to know whether the URL being loaded is an ad or not (not breaking content blockers is an invariant of the fenced frame design). Therefore, a fenced frame needs to act as an iframe so the ad blocker can cross the fence and work as expected. See the integration with extensions explainer document for more details.

Disable in fenced frames.

If a feature needs to know about something outside of a fenced frame to function properly, but it’s impossible to expose that information without introducing a leak, the only option is to disallow the feature inside a fenced frame entirely.

  • Permissions policies inherit from a frame’s parent. For cases where the url loaded in the fenced frame is not set by the embedder, we need to make sure other ways of communicating information are restricted. By delegating permissions, a fenced frame is allowed to learn what its parent’s permissions policy is (either through their headers or through the allow=”” attribute in the frame object), which opens the door to fingerprinting. Tests can easily be written in JavaScript to determine whether a policy is enabled or disabled. So, to prevent that, inheritance needs to be disabled in a fenced frame.
    • With the opaque ads configuration design, setting permissions policies will be allowed in a fenced frame. However, the actual policies will be checked by a k-anonymity check, and the URL will not win the FLEDGE auction and not load in the frame if it fails the check. This has the effect of decoupling this information from the parent frame. While the fenced frame will learn about the permissions it was allowed to be created in, it won’t know which ones came from the page and which ones came from FLEDGE, and they are guaranteed to be k-anonymous enough for fingerprinting to not work.
  • Modifying parameters in a fenced frame (such as the dimensions of the frame or its mode) is an easy way for an embedding page to pass information through the fence. Modifying parameters requires information to be passed from an embedding page into the fenced frame, but as soon as a parameter is modified, the fenced frame can easily access it. So, modifying parameters needs to be disabled in a fenced frame.
    • In the case of resizing a fenced frame, we do allow the resizing call to go through. However, this only resizes the outer frame in a fenced frame. The inner frame retains its original dimensions, but is visually scaled to fit in the new outer frame. As far as the page embedded in the fenced frame is concerned, its dimensions did not change.
  • Navigating a fenced frame to a URL like a “javascript:” url could allow arbitrary data to flow across the fence. So, this is disabled in a fenced frame.

Writing Tests

There are 2 instances where you will need to write tests to ensure your feature works as expected with fenced frames:

  • If it is possible for the web platform to gain access to information from your feature (regardless of whether you disable the feature or have fenced frames act as a main frame), then you will need to write a test to make sure that the information can’t be leaked across a fenced frame boundary.
    • If you are disabling your feature, the test can be as simple as making sure the feature doesn’t work inside a fenced frame.
    • If you are having your feature act as a main frame, the test should ensure that your feature is not introducing information to a fenced frame that changes if the conditions of the embedding frame change.
      • For example, window.top works inside a fenced frame, but it just returns the fenced frame root. To ensure that this is working correctly and not actually returning the outermost main frame, there should be a test confirming this behavior.
  • If you are having a fenced frame act as an iframe for your feature, you will need to write a test to ensure that the feature is working properly inside a fenced frame. This test can be as simple as triggering the feature in a fenced frame and verifying the output is what you expect it to be.

There is already infrastructure set up to help you write fenced frames tests.