Description
Currently the navigate algorithm assumes it is always passed a sourceDocument. This is used for:
- Checking if the source is allowed to navigate the target by sandboxing
- Setting the initiator origin for the navigation. This is used:
- When deciding what the origin should be if the URL is about:blank
- For displaying to the user if the navigation ends up triggering external software (e.g.
some-external-app://foo
) - For preventing cross-origin-domain javascript: URL navigation and creating the resulting document
- Creating the source snapshot params, including:
- "has transient activation", which affects
Sec-Fetch-User
; - "sandboxing flags", used as part of the allowed-to-navigate check;
- "allows downloading", which affects whether navigating to a
Content-Disposition: attachment
will succeed; - "fetch client", which affects a number of things in the Fetch algorithm, e.g. referrer calculation; and
- "source policy container", which is used as the default policy container for the resulting document for local URLs
- "has transient activation", which affects
However, for browser UI-initiated navigations, we don't set any sourceDocument. So, that's bad; many algorithms are actually broken.
You might think we could treat browser UI navigations as if the source document is navigating itself. This works in some cases, e.g., it bypasses the allowed-by-sandboxing check. But it doesn't work for others; e.g., if the user navigates to a Content-Disposition: attachment
URL, it should work, even if the page currently being displayed has sandboxing flags that disallow downloads.
So I think we need to allow sourceDocument to be null for browser UI navigations, and figure out replacements for all of the things derived from it. Ideas:
- Skip the allowed-by-sandboxing check
- Initiator origin: ???
- Source snapshot params
- Has transient activation: should be true always, assuming the user is the one that interacted with the browser UI. This is part of Sec-Fetch-User and Sec-Fetch-Site for user-initiated UI navigations w3c/webappsec-fetch-metadata#71.
- Sandboxing flags: an empty set of flags
- Allows downloading: true
- Fetch client: ???
- Source policy container: null. (The field currently doesn't allow null, but its one usage site would work fine here, I think.)
OK, so the hard ones are initiator origin and fetch client. Ideas:
-
initiator origin: I think we want a new opaque origin for top-level about:blanks or
javascript:'a string'
. We don't want to tell the user "an opaque origin is attempting to navigate you tosome-external-app://foo
" if the user themselves typed the URL in the URL bar, so we might need a bit of special casing here. -
fetch client: maybe, leave the client as null and try to fill in the fetch fields directly? Per this section of Fetch, those would be:
- origin: a new opaque origin?? Will this break Fetch and cause various security checks to fail?? Maybe we should pick the target URL's origin instead?
- policy container: an empty policy container
- service-workers mode: "all"
- referrer: "no-referrer"
I'm willing to put up a PR for this, but I'd love some confirmation that I'm on the right track here before I do. Any thoughts from @annevk @smaug---- @domfarolino @jakearchibald ? Especially @annevk for the Fetch integration questions