html icon indicating copy to clipboard operation
html copied to clipboard

Prevent top navigations without user activation in some circumstances?

Open domenic opened this issue 3 years ago • 2 comments

I'm still investigating exactly what is going on here, but between https://github.com/WICG/interventions/issues/16 and https://chromestatus.com/feature/5851021045661696 there is some indication that Chrome shipped a restriction on how much iframes can navigate the top-level frame, beyond the currently-specified restrictions based on sandboxing.

I have found some evidence that:

Supposedly Chrome shipped this in Chrome 68, but every few releases someone shows up in https://github.com/WICG/interventions/issues/16 complaining that something new is broken, so it's not clear exactly what Chrome is doing here.

We should:

  • Figure out exactly what Chrome has implemented
  • See if other browsers are interested in doing so as well
  • If so, spec it and write WPTs.

/cc @natechapin @shivanigithub

domenic avatar Jun 15 '22 15:06 domenic

We're interested in implementing this in Gecko. Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1800190

zcorpan avatar Apr 09 '25 11:04 zcorpan

CC @annevk, it seems Safari also ships this or a variant of this? https://bugs.webkit.org/show_bug.cgi?id=193076

mozfreddyb avatar Jun 18 '25 13:06 mozfreddyb

Looks like https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/web_tests/http/tests/security/frameNavigation/ has a number of tests that could maybe be adopted. It appears we implemented this quite a while back to address attacks from ads observed in the wild.

One thing I noticed that isn't mentioned here is that there's a carve-out if the navigation is same-site with the iframe and there's a carve-out for sandboxed iframes. (The relevant code in WebKit seems quite readable by the way, worth looking at https://commits.webkit.org/207754@main and more recent versions of those files when specifying this.)

annevk avatar Jun 23 '25 10:06 annevk

@domfarolino, you mentioned that you might be available to work on this. I don't mean to commit you if that's changed.

jyasskin avatar Sep 24 '25 21:09 jyasskin

Here is roughly how we implemented it in Firefox:

  1. Before a target BrowsingContext (BC) is navigated, perform the following checks:
    1. If the target BC is not top-level, return OK
    2. If the load has transient user activation, return OK
    3. If the source BC has sticky user activation, return OK
    4. If the source BC and the target BC are not part of the same BC tree, return OK
    5. If the source BC and target BC are same-origin, return OK
    6. If the source BC is embedded with “allow-top-navigation”, perform the following checks:
      1. If the source BC has no parent, return OK
      2. Otherwise, set sourceBC = sourceBCParent and go to 1.v.
    7. Otherwise, return ERR

The function performing all the checks can be found here: https://searchfox.org/firefox-main/rev/529fecf1aff6e290cac16b106edfb656db6f5088/docshell/base/BrowsingContext.cpp#2018.

@maltejur worked on the web platform tests which were added here: https://github.com/web-platform-tests/wpt/pull/54792.

moz-mdauer avatar Sep 25 '25 10:09 moz-mdauer

Sorry for the late reply.

The chromium logic is primarily starting here.

Going through your steps:

  1. If the target BC is not top-level, return OK

line 2267

  1. If the load has transient user activation, return OK

I can't find this explicitly. I think we rely on stick user activation alone, and may have weird corner cases where the transient user activation was from a different browsing context.

  1. If the source BC has sticky user activation, return OK

line 2271

  1. If the source BC and the target BC are not part of the same BC tree, return OK

Included in the same check as (1) on line 2267.

  1. If the source BC and target BC are same-origin, return OK

line 2272

  1. If the source BC is embedded with “allow-top-navigation”, perform the following checks:>
    1. If the source BC has no parent, return OK
    2. Otherwise, set sourceBC = sourceBCParent and go to 1.v.

chromium's allow-top-navigation logic is irritatingly spread around. But I think we're close enough.

The OK cases not listed here but present in chromium are:

  1. If popups are allowed (line 2289)
  2. If target BC and source BC have the same eTLD+1 (lines 2277-2287)

natechapin avatar Oct 24 '25 21:10 natechapin