Closed Bug 1638612 Opened 5 years ago Closed 3 years ago

changing window.open().location: URL bar updates on load start not on new document context instantiated

Categories

(Firefox for iOS :: General, defect)

Other
iOS
defect

Tracking

()

RESOLVED WONTFIX

People

(Reporter: rayyanh12, Unassigned)

References

Details

(Keywords: csectype-spoof, sec-moderate)

Attachments

(3 files)

Attached file Parent.html

User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36

Steps to reproduce:

  1. Go to parent.html
  2. Click on the hyperlinked text
  3. Observe.

Actual results:

Shown epicgames.com while the content is of google.com

Expected results:

Update the content too.

Attached file attack1.html

Second part of the attack. Upload both files at a web directory.

Attached video firefox.mp4

Is there any way to attach multiple files at once? Anyway, this is the attack video.

This might be the same underlying "when do we update the URL display" problem as the other bugs you've filed recently. Different techniques to trigger the problem, but the same underlying issue.

Flags: needinfo?(gkeeley)

I tried to repro and couldn't yet. Looks like a timing attack on WKWebView's URL updating events.
Client apps get events with the URL is updated, however, the display of the URL should only update when the new document has been instantiated and thus the old one purged. This has been buggy in the past.

function f() {
	w = window.open("attack1.html", "_blank", "width=500 height=500");
	i = setInterval("try { x = w.location.href; } catch(e) { clearInterval(i); n = 0; next(); }", 5);
}

This retains a reference to the opened window, and then tries to set its location with a timer attack.
WebKit blocks window.open("another origin").location = newLoc, by cross-origin policy.
I might need a simpler repro case to get this to happen, and to understand better what is happening here.

Flags: needinfo?(gkeeley)
Summary: URL spoofing → window.open cross-origin timing attack to URL spoof

Similar bug in Safari desktop, it partially reproduces as the window opened will change title to www.epicgames.com, it does seem to block loading of the content, however this isn't how Safari normally blocks illegal cross-origin API calls, it should be a no-op, not a partial op.

And Safari iOS has the same bug entirely, it fails to block window.open(...).location = ... as a cross-origin request.

Reporter: have you filed this as webkit sec bug? Certainly seems like a partial failure on desktop webkit, and definitely a bug on iOS webkit.

Flags: needinfo?(rayyanh12)

Daniel: can you grok what I put in this bug, as in, am I understanding cross-origin restrictions on the opener of var opener = window.open() correctly?

Flags: needinfo?(dveditz)

no, I haven't. Have reported similar bugs to them though

Flags: needinfo?(rayyanh12)
Summary: window.open cross-origin timing attack to URL spoof → window.open cross-origin timing attack to URL spoof (WebKit bug)

it fails to block window.open(...).location = ... as a cross-origin request.

This is, unfortunately, legal -- grandfathered in from the early days of the web before the same-origin policy was fully formed. If you have a window (or iframe) reference you can always navigate it through the location object (specifically location.href and the shortcut of assigning a string to the location), even if all other uses of that location object throw a cross-origin security error. To give you an idea what you're up against, the HTML spec says the following :-)

WARNING! The Location exotic object is defined through a mishmash of IDL, invocation of JavaScript internal methods post-creation, and overridden JavaScript internal methods. Coupled with its scary security policy, please take extra care while implementing this excrescence.

I don't think that's the problem here. Once the parent script detects that the second window has navigated the first time (when reading the location throws a SOP security error) it starts spawning an infinite number of timeouts constantly loading a new URL (with a cache-busting param) so that nothing ever really loads. (On desktop this locks up a child process -- annoying DoS.)

It appears we're changing the URL when we start loading, which means that until the load finishes we're showing the new URL over the old content. A tempting alternative would be to wait until the new content finishes layout -- but then that means if you can stall finishing then you've got the OLD url on top of the NEW content.

We don't want to do either of those, we don't want to show the NEW url until we get rid of the old content. I don't know what events we get from WKView. We don't want to change the URL based on network events, but do we know when the web view starts layout (clears the old content)? If not maybe we just have to display no URL at all until we know the page has finished loading (people won't really like that, though).

Flags: needinfo?(dveditz)

Thanks Daniel, note to self:
let w = window.open(...);
w.location // fails, getter is blocked
w.location = 'http://www.google.com' // setter is ok

It appears we're changing the URL when we start loading, which means that until the load finishes we're showing the new URL over the old content.

That would be a bug as we don't change the URL on load start, yet it does seem to be the case here. We have appropriate WKWebView events we should be using to ensure the old main document is purged and a new one instantiated, along with a fresh JS context for the new document. Hopefully there isn't some intractable bug in WKWebView that only shows up when a parent window changes the child window URL.

Summary: window.open cross-origin timing attack to URL spoof (WebKit bug) → changing window.open().location: URL bar updates on load start not on new document context instatiated
Summary: changing window.open().location: URL bar updates on load start not on new document context instatiated → changing window.open().location: URL bar updates on load start not on new document context instantiated

The severity field is not set for this bug.
:garvan, could you have a look please?

For more information, please visit auto_nag documentation.

Flags: needinfo?(gkeeley)
Flags: needinfo?(gkeeley)

The severity field is not set for this bug.
:garvan, could you have a look please?

For more information, please visit auto_nag documentation.

Flags: needinfo?(gkeeley)
Flags: needinfo?(gkeeley)
Severity: -- → S3

I am not convinced there is a bug here.
This is the flow of loading the page in WKWebView:

  • request to change the URL
  • page begins loading, resets the JS Context to the new document, starts loading DOM (old page no longer exists)
  • notify clients using webView(_ webView: WKWebView, didCommit navigation: WKNavigation!)` that URL has now changed
  • start rendering to the screen, only now does the old page disappear and the new one start drawing

The attack here is the keep changing the URL before the rendering starts. When browsing in Firefox or Safari on iOS one can see the URL updates a split-second before the new DOM is rendered (and this issue is a timing attack that keeps changing the URL during that time window). There is no 'turning back' at this point, the prev page is no longer interactive and the new page won't be interactive until it renders.

My question is, is it ok that the URL is updated before rendering begins? It seems like this is by-design in WebKit.

We'll close this issue for now, please let us know if you think otherwise.

Status: UNCONFIRMED → RESOLVED
Closed: 3 years ago
Resolution: --- → WONTFIX
Group: mobile-core-security
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: