-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Newly created browsing contexts will almost always reject history.pushState/replaceState #6836
Comments
Ah, interesting. So there are three checks that are naturally possible:
Some examples:
In a vacuum, absent compat concerns, adding something like (2) or (3) (probably (3)) might be reasonable. Chrome code has an origin check, but it's rather complicated with several exceptions. It mentions https://bugs.chromium.org/p/chromium/issues/detail?id=528681 as a compat concern. So if we did do something it probably couldn't be as simple as (2) or (3). WebKit code looks similar to Chrome but easier for me to read at least. I'm not sure if they're equivalent. Firefox code seems to be attempting to do (1) but because it implements it using URL origin check + username/password check, it mixes in a bit of (2), which impacts the Getting interop/spec/tests here would be good. I'm unsure what direction is best to go in though. |
Thanks for investigating! Looks like Looking at the Chrome bug about unique origins changing the fragment through replaceState and the comment in the spec mentioning spoofing, I think we need to keep allowing all URLs that are "same-url-excluding-fragments with the document URL" so that opaque origins (and other special origins that's not really in the spec) can continue changing the fragment through the API. But does that mean the origin of the document should change too? Maybe not since opaque origins don't depend on the exact URL? I think we can either keep the "same URL except for query/path/fragment" path compare the URL's origin against the document's origin like we do now, or change it to use the "origin of the document if we navigate to this URL from this frame", not the URL's origin which is purely based off the URL. I guess we can get this by calling "determine the origin" with the current browsing context, target URL, current document's sandbox flags, and current document's origin?
Anyways this is sounding more like an implementation bug now, so I'm fine not changing anything in the spec and I'll just file relevant impl bugs! |
Fixing implementations sounds great if you're willing to do so for Chrome/file bugs for others! I worry a bit that this would be relaxing a security check, but I can't think of any actual problem that would be caused by moving to behavior (1), so I look forward to your attempt. |
@rakina, can you work to confirm that updating to match the spec here is something Chrome is interested in doing, if possible? Maybe get confirmation from security folks that it should be OK? @smaug---- @cdumez for the same question for Gecko/WebKit. |
I've filed a bug for Chrome, with a simpler proposal to just do something like this:
I think this is an easy change for the current implementations, compared to my previous proposal of having a way to determine "origin of the document if we navigate to this URL from this frame" (but reading WebKit's code, this might be closer to what they're doing through the Curious what @smaug---- and @cdumez thinks :) |
So to be clear, your proposal is something a bit more strict than the current spec, which is just
In particular, the current spec allows changes such as Also, I am pretty sure your proposal is equivalent to the following:
which to me at least is a bit clearer. |
I think the current spec is a bit different due to step 6.5: it doesn't allow path/query changes when the new URL origin is different than the current document origin (so this disallows I think your proposal is a bit different in cases where the document's origin is not opaque but the target URL creates an opaque origin, e.g. current document is Maybe this is equivalent to my proposal, though I'm not 100% confident on my origin knowledge:
|
Oh, wow, I totally missed that since the beginning of this thread. Oh dear. A lot of what I've said has been based on a misunderstanding. So for example, the current spec disallows changing from So the main issue here is that the spec is not as lenient as browsers in some cases. Here is how Chrome compares to the spec: if (document_origin->IsOpaque() || document_origin->IsLocal()) {
// This check is not in the spec
can_change = EqualIgnoringQueryAndFragment(url, document_url);
} else if (!EqualIgnoringPathQueryAndFragment(url, document_url)) {
// This check is step 6.4
can_change = false;
} else if (requested_origin->IsOpaque() ||
!requested_origin->IsSameOriginWith(document_origin)) {
// This check is the same as step 6.5
can_change = false;
} (I am pretty sure the So I think we have three options:
I don't have a strong preference between the last two. Maybe it's time to start writing a bunch of test cases? That way we could figure out what cases are allowed everywhere, and what cases are disallowed everywhere, without having to do a bunch of tricky reasoning and code inspection. |
Since this also impacts app history, I am happy to spend some of my time on writing the test cases. |
Having tests would be great! I think Safari might be more lenient than Chrome (judging from the |
Yes, I noticed this today too :( |
I wrote some tests, with the tests checking against the current spec. (I'm pretty sure... it took a few rounds for me to figure it out.) Let me know if you can think of other interesting cases I missed! Here are the departures between the spec and implementations:
An interesting thing to note here is the inconsistency of Chrome with regard to how safe it considers query- and hash-only changes:
My recommendation is to not special-case opaque origins or local schemes. That is, just modify the current spec to allow query differences if the origin is different. This is equivalent to @rakina's proposal in #6836 (comment) I believe. Then:
|
Thanks for the WPTs! I think changing the implementation in Chrome to match the recommendation should be easy, except for the BTW I noticed the WPTs don't test |
Oh, oops. That is what the spec does as well. So those tests are just invalid. I will update them and the above. Sadly |
The actual normative change here is to allow the query component to change in the cross-origin case, not just the fragment component. However, while we're here, we pull out the algorithm into a standalone definition, and rephrase it to be clearer with fewer nested negative conditions. This better aligns with browsers, exactly matching WebKit and being only slightly more lenient than Chromium and Gecko. See the full analysis at #6836 (comment). This also improves the domintro for pushState()/replaceState() to be a bit more in line with modern style, and to explain the error condition. Closes #6836.
This allows the query component to change in the cross-origin case, not just the fragment component. This better aligns with browsers, although not exactly with any particular browser, since browsers seem to special-case opaque origins. See the full analysis at #6836 (comment). Closes #6836.
We discussed this today and @annevk had a counterproposal, which would roughly be like this:
(I believe there is no origin check in @annevk's version.) This is substantially stricter than Firefox, Chrome, and Safari in most cases, so there might be some compat risk. But, it is all in weird cases like This is also more lenient than Chrome and Safari in the particular case of allowing sandboxed iframes to have their paths rewritten. So there might be some security concerns there. @rakina, what do you think of @annevk's proposal? I still somewhat prefer #6992 as it seems like a nice simple rule; in particular I find varying on scheme somewhat aesthetically displeasing compared to just doing an origin check. But maybe it'd be easier to get interop if we went with @annevk's preference. |
To be clear, the reason I favor varying on scheme is because where the actual authority sits with a URL depends on it. For HTTP(S) URLs it's scheme/host/port. For file URLs it's scheme/host/port/path. For data and blob URLs it's scheme/path/query (they never have a host/port). For about:blank it's arguably scheme/path, so we could group it with file if we wanted to I suppose. Other schemes you cannot really navigate to. |
Being more lenient with sandboxed frames sounds a bit concerning, but I guess security checks for things are already based on origin instead of URL so maybe it's OK? A sandboxed main frame can also now affect the path part in the browser omnibox. Maybe that's not so bad since we already allow it to change the query and fragment anyways.. Do we know why we have the special concern about sandboxed frames to begin with? Other than that, I think it sounds reasonable. |
It seems the change was made in e5ace39. I cannot find any rationale for this change in https://lists.w3.org/Archives/Public/public-whatwg-archive/2010Jan/. I suppose the theoretical issue is that a |
Thanks for looking that up! OK then, @annevk's proposal sounds good to me. |
…ing, a=testonly Automatic update from web-platform-tests Tests for history.pushState() URL rewriting See whatwg/html#6836. Follows whatwg/html#7044. -- wpt-commits: 130d57f9a1d6f4f51bb9bd81444978efad7016ce wpt-pr: 30182
…ing, a=testonly Automatic update from web-platform-tests Tests for history.pushState() URL rewriting See whatwg/html#6836. Follows whatwg/html#7044. -- wpt-commits: 130d57f9a1d6f4f51bb9bd81444978efad7016ce wpt-pr: 30182
Closes whatwg#6836. Closes whatwg#6992 by superseding it.
Discovered while working on web-platform-tests/wpt#28541.
When a new browsing context is created, it will load the initial about:blank document with URL set to
about:blank
, but its origin will be set to the creator's origin. So this means the URL and the origin can be quite different (unless the opener's origin isabout:blank
).When the document URL and the origin differs, apparently
history.pushState()
orhistory.replaceState()
will always result in aSecurityError
. This is because of the checks that compare the target URL against both the document URL and the origin. If the document URL and origin differ, one of the checks will always fail. Example test cases that fails in browsers:I wonder if this is intended? Maybe we can drop the comparison against the document URL, and just compare the origin? Or maybe we should special case cases where the document URL & origin differs? I'm worried that this case in general is not handled well in other parts of the spec.
cc @domenic
The text was updated successfully, but these errors were encountered: