Closed mikewest closed 4 years ago
This should be pretty easy to add now.
Poking at this today. For frame-ancestor
, I expect to add the relevant hooks to CSP, and, then call them from https://html.spec.whatwg.org/#process-a-navigate-response. For X-F-O
, I'll make up something that at least somewhat aligns with RFC7034.
"Pretty easy to add", he says.
Basically, we didn't think about this enough, and it's more subtle than I though, because we need the source browsing context's policy in some cases (form-action
), and the target browsing context's parent's policy in others (frame-src
), and the response's policy in still others (frame-ancestors
). I think these two hooks give me the tools I'll need to poke at things in CSP, but I wonder if there's a better way...
WDYT?
One way to do form-action is to just hook it directly in form submission. And just navigate to a network error if it blocks. If it's specific to forms invoking navigate we might as well keep it there.
The others remain complicated.
Hooking directly into form submission wouldn't catch redirects, would it? I think we need to live in navigate for that to work.
Good point.
Are you waiting on me for this PR? (Sorry, I've been out for almost two weeks, so I'm trying to page this back in....)
Yeah, the review comments are not addressed yet I thought.
Today @travisleithead discovered that Chrome does not support the ALLOW-FROM variant. Edge had strict parsing, which broke when it encountered a web site with ALLOW-FROM=https://example.com/
.
If we do manage to get around to speccing this, so that nobody else runs into these sorts of interop issues while building their browsers, we'll need to figure out what to do with ALLOW-FROM. Probably also questions around whitespace trimming etc. So yeah, not just semantic issues, also syntactic ones :(
As mentioned in https://bugzilla.mozilla.org/show_bug.cgi?id=1599256 this should also define what kind of document does get loaded ( and whether that creates a about:blank
?)load
event. (That's what Firefox will implement unless Chrome starts treating this as a network error soon.)
Last I checked, Chrome (and WebKit) loads an error page with an opaque origin (data:...
in WebKit, and chrome://interstitial
(I think) in Chrome), and does fire onload
when a page is blocked via XFO (note that Chrome has different behavior for CSP's frame-ancestors
because that's still handled in our renderer, but it's moving out to the browser in ~80, and aims to have the same behavior as XFO).
Ah, I guess Chrome in general fires the load
event for network errors? I.e., I get it both for https://expired.badssl.com/
and https://google.com
. Maybe that's reasonable enough.
Yes, that's my understanding of Chrome's (and WebKit's, I believe) behavior. We move network errors to an opaque-origin'd error page, and fire an onload
.
I'm interested in tackling this in the near future.
It looks like currently frame-ancestors is completely handled, right? That is, https://html.spec.whatwg.org/#process-a-navigate-response step 1 handles frame-ancestors (and other CSP checks, like form-action and frame-src). It creates a network error. Network error pages have an opaque origin (clearer after #5736) and fire a load event (per https://html.spec.whatwg.org/#read-ua-inline "stopped parsing" step).
So this bug reduces to only X-Frame-Options handling. There'll be a bit of trickiness around parsing, but otherwise it should be pretty straightforward once parsed. Assuming we don't support ALLOWFROM
(tests needed), then we should have all the info we need. Something like:
The last step only checking top-level origin (instead of all intermediate origins) is based off of the remarks in https://w3c.github.io/webappsec-csp/#frame-ancestors-and-frame-options about "many user agents"
Hmm per the discussions in https://bugzilla.mozilla.org/show_bug.cgi?id=725490 it looks like Chrome and Firefox implement all-ancestors checking, which is nice. And everyone passes the associated WPTs. https://wpt.fyi/results/x-frame-options?label=master&label=experimental&aligned&q=x-frame-options
So I've got an initial spec for this up in https://github.com/whatwg/html/pull/5737. The question remains on what to do in "conflict" cases like DENY,SAMEORIGIN
. Per the description of Chrome's algorithm in https://github.com/web-platform-tests/wpt/pull/21730#issuecomment-585161928, and the test results in https://github.com/web-platform-tests/wpt/pull/21730 and https://github.com/web-platform-tests/wpt/pull/24618, we could expand https://github.com/whatwg/html/pull/5737 with something along the following lines:
(this is meant to be equivalent to the algorithm @mikewest outlines, but with more clarity at the cost of more O(n) operations. We could also just use the Chrome algorithm as-is.)
Note that this conflict cases, according to Chromium metrics back in February, affects 0.002% of page loads.
I'm OK with either the current simple spec proposal in https://github.com/whatwg/html/pull/5737 (which I believe matches Firefox behavior), or with the more complicated Chromium version. I like simplicity, but I am sympathetic to the argument that conflicts are a sign that something has gone wrong and we should err on the side of blocking. Also, blackbox testing indicates that the Chromium model and the Safari model are probably the same, so it might be easier to just align there.
What would Mozilla prefer? /cc @mozfreddyb
EDIT: further testing reveals that the above algorithm proposal doesn't seem quite correct. In particular invalid,sameorigin
blocks same-origin framing in Chrome and Safari but the above algorithm would let it through.
Alright. I did another pass through the tests, and rewrote everything to be less copy-pastey, and made sure that every same-origin test has a corresponding cross-origin test. Results over at https://github.com/web-platform-tests/wpt/pull/24618.
Here is the current status of browsers vs. the spec draft in https://github.com/whatwg/html/pull/5737:
Firefox has a timeout failure on "DENY blocks cross-origin framing with CSP frame-ancestors 'self'". Not sure what could be going on there.
Safari and Chrome both treat the presence of any invalid tokens, along with valid ones, as causing the result to be treated as DENY. Firefox and the proposed spec ignore invalid tokens.
I don't have strong feelings about which model is better. The proposed spec is simpler, but it seems like the Chrome and Safari behavior might be a bit more strict, which could be good.
/cc @dveditz
/cc @ArthurSonzogni who I noticed working a bit on XFO in Chromium recently.
Given the lack of engagement from implementers here I've decided the simplest course is to match the spec to 2/3 browsers and get things merged. I'll work on the spec/test updates for that now.
See https://github.com/whatwg/fetch/issues/302 where I initially filed this request. @annevk's suggestion that we handle the header inside the navigation algorithm (probably as step 21, after the response checks?) SGTM.
This will require some changes to CSP as well to move
frame-ancestors
from a response check in Fetch to a new check in the navigate algorithm.