Loads triggered by content scripts can be used to bypass X-Frame-Options
Categories
(Core :: DOM: Security, defect, P2)
Tracking
()
Tracking | Status | |
---|---|---|
firefox-esr68 | --- | unaffected |
firefox75 | --- | wontfix |
firefox76 | --- | wontfix |
firefox77 | --- | verified |
People
(Reporter: robwu, Assigned: ckerschb)
References
(Regression)
Details
(Keywords: regression, sec-low, Whiteboard: [domsecurity-active] [post-critsmash-triage][adv-main77-])
User Story
Extension _pages_ should be allowed to frame XFO/CSP-with-frame-ancestors content as if they were browser UI. Normal web pages should never be allowed to frame such content, even if a privileged script (web extension or chrome) put it there.
Attachments
(3 files)
In bug 1595652, a change was made to allow extensions to load frames in extension pages, even if normally blocked by XFO. An undesired side effect of the change is that the mechanism allows content scripts to bypass XFO.
The check needs to be more strict, to only allow extensions to bypass XFO if the load is inside the extension process, or similarly, if the top-level is the extension's principal.
STR:
- Visit
about:debugging
and load the attached add-on. - Visit https://example.com
- The extension loads a frame. Look at the frame's content and optionally the console of the tab's devtools.
Expected:
-
The frame should be blank. The console of the tab's devtools should show:
Load denied by X-Frame-Options: “SAMEORIGIN” from “https://www.amazon.com/favicon.ico”, site does not permit cross-origin framing from “http://example.com/”.
Actual:
- The frame shows Amazon's favicon.
Comment 1•5 years ago
|
||
Need to check CSP frame-ancestors -- I believe the code for that and XFO have not been merged yet but they should behave the same. moz-extension:// pages should be able to force-frame XFO pages just as browser UI can, but privileged scripts (system or extension) should not be able to cause XFO pages to load in a normal-page frame.
Reporter | ||
Comment 2•5 years ago
|
||
(In reply to Daniel Veditz [:dveditz] from comment #1)
moz-extension:// pages should be able to force-frame XFO pages just as browser UI can,
Note that just comparing the document/principal's URL against moz-extension:
is not sufficient. Pages from extensions that use web_accessible_resources
can also be embedded by web content. These embedded pages are not as privileged as extension pages, and it should not be possible to bypass XFO via them.
Assignee | ||
Comment 3•5 years ago
|
||
Boris, it seems currently we use loadInfo->TriggeringPrincipal()->GetIsAddonOrExpandedAddonPrincipal() [1] to determine whether a load was triggered by an extension and hence should bypass x-frame-options check. Unfortunately, using that principal check also allows content scripts to bypass XFO. Is there a good and easy alternative, so we could basically simply replace loadInfo->TriggeringPrincipal()->GetIsAddonOrExpandedAddonPrincipal() with a better check to get the desired behavior?
![]() |
||
Comment 4•5 years ago
|
||
The triggering principal is the thing that started the load, right? That doesn't seem like the right thing to be checking if we want to disallow extensions putting things in content pages.
What is the loadingPrincipal in these "extension navigates a subframe of a webpage" cases? Is it the extension or the webpage? What is it when the load is in the cases when we do want to bypass XFO?
If an extension loads a content page inside itself and then loads a subframe inside that page, should XFO apply to that subframe, by the way? Comment 0's "if the top-level is the extension's principal" makes it sound like "no", but it's not clear to me that this is what Rob actually meant to say...
Assignee | ||
Updated•5 years ago
|
Reporter | ||
Comment 6•5 years ago
|
||
(In reply to Boris Zbarsky [:bzbarsky, bz on IRC] from comment #4)
If an extension loads a content page inside itself and then loads a subframe inside that page, should XFO apply to that subframe, by the way?
I'd say yes, to have a secure default.
Comment 0's "if the top-level is the extension's principal" makes it sound like "no", but it's not clear to me that this is what Rob actually meant to say...
XFO should be respected as much as possible, except for the special case when a privileged extension page attempts to embed the frame (bug 1595652).
As mentioned in comment 2, just checking the principal (of the frame host / request initiator) is not sufficient, because moz-extension:
-pages are unprivileged when embedded as a document in a different frame. This means that the top-level principal (and more generally: all ancestors) should have the same moz-extension:
-principal.
Comment 7•5 years ago
|
||
The "all ancestors have the same moz-extension:
principal" function we use to determine if something is a privileged extension page is [1], but the full check confirms the process as well [2].
https://searchfox.org/mozilla-central/rev/5a52cec97c/toolkit/components/extensions/ExtensionPolicyService.cpp#418
https://searchfox.org/mozilla-central/rev/5a52cec97c/toolkit/components/extensions/ExtensionPolicyService.cpp#476
I'm not sure we can easily get to the window from the aChannel
in FramingChecker::CheckFrameOptions, though down the line with Fission, this whole check might boil down to just confirming the correct process.
Assignee | ||
Comment 8•5 years ago
|
||
Rob, I finally found some time to look into this problem with some more care. I can reproduce using the provided xfo-bypass.zip
. As discussed on slack one possible option would be to traverse all the documents up to the root and check that all NodePrincipals are of type 'moz-extension'. I incorporated that idea in the attached patch.
Now here is the catch:
The attached patch fixes the problem in the testcase, but mostly because of those three lines:
if (!aLoadInfo->TriggeringPrincipal()->SchemeIs("moz-extension")) {
return false;
}
In other words, it seems GetIsAddonOrExpandedAddonPrincipal() returns a different result than Principal()->SchemeIs("moz-extension"). Is that expected? Put differently, would it suffice to just update the GetIsAddonOrExpandedAddonPrincipal() to check for moz-extension like in the patch or do we still need to travese all the way up to the root document?
FWIW, after writing the patch I realized that XFO is enforced in the parent, so I don't think we can actually query the Document. If the fundamental idea of the patch is right however I think we could add some information about the scheme to the browsingContext.
Reporter | ||
Comment 9•5 years ago
|
||
In other words, it seems GetIsAddonOrExpandedAddonPrincipal() returns a different result than Principal()->SchemeIs("moz-extension")
This is expected and desired. Content scripts have an Expanded principal, and we shouldn't allow them to bypass XFO.
Currently you're allowing nested moz-extension URLs from different extensions to bypass XFO. I would make the condition even stricter.
Content in a frame can only bypass XFO if the parent is a moz-extension:-principal (principal, to allow about:blank but rule out sandboxed frames), and all ancestors until the top have the same principal.
Such logic could also be useful for other situations, from https://bugzilla.mozilla.org/show_bug.cgi?id=1629436#c7
FYI: using triggeringPrincipal to make decisions may not always result in the desired behavior for add-on devs (too strict). That's not a concern for this bug, but you may be interested in https://bugzilla.mozilla.org/show_bug.cgi?id=1595652#c6 .
Reporter | ||
Comment 10•5 years ago
|
||
As seen in https://bugzilla.mozilla.org/show_bug.cgi?id=1595652#c11 , the patch there was misguided.
I'm in favor of just reverting https://hg.mozilla.org/mozilla-central/rev/2ac103491660 to fix this issue. Do you agree?
Assignee | ||
Comment 11•5 years ago
|
||
(In reply to Rob Wu [:robwu] from comment #10)
I'm in favor of just reverting https://hg.mozilla.org/mozilla-central/rev/2ac103491660 to fix this issue. Do you agree?
I think that makes the most sense in the end. I just reverted that change and testet:
(a) https://bugzilla.mozilla.org/show_bug.cgi?id=1619338#c0 -> The frame gets correctly blocked by XFO.
(b) https://bugzilla.mozilla.org/show_bug.cgi?id=1595652#c0 -> The extension popup works correctly.
Assignee | ||
Comment 12•5 years ago
|
||
Reporter | ||
Comment 13•5 years ago
|
||
(In reply to Christoph Kerschbaumer [:ckerschb] from comment #11)
(In reply to Rob Wu [:robwu] from comment #10)
I'm in favor of just reverting https://hg.mozilla.org/mozilla-central/rev/2ac103491660 to fix this issue. Do you agree?
I think that makes the most sense in the end. I just reverted that change and testet:
(a) https://bugzilla.mozilla.org/show_bug.cgi?id=1619338#c0 -> The frame gets correctly blocked by XFO.
As expected from the change :)
(b) https://bugzilla.mozilla.org/show_bug.cgi?id=1595652#c0 -> The extension popup works correctly.
That's because the extension already uses the webRequest API to remove the X-Frame-Options header. It would have worked regardless of the original patch.
![]() |
||
Comment 14•5 years ago
|
||
https://hg.mozilla.org/integration/autoland/rev/a9df87dcb3919493299e9c601ca1151f9bddd4a2
https://hg.mozilla.org/mozilla-central/rev/a9df87dcb391
Updated•5 years ago
|
Updated•5 years ago
|
Comment 15•5 years ago
•
|
||
Hi,
I have managed to reproduce the initial issue using Beta build 76.0 (build id: 20200429185419) using Windows 10.
In latest Nightly 77.0a1 (build id: 20200503214759) the following message is displayed inside the frame:
"Blocked by X-Frame-Options Policy
An error occurred during a connection to www.amazon.com.
Nightly prevented this page from loading in this context because the page has an X-Frame-Options policy that disallows it."
From comment 11 and comment 13 I assume this is the expected behavior now, but before marking this as verified,@Christoph can you please confirm this?
Thanks.
Reporter | ||
Comment 16•5 years ago
|
||
Hi Alin, which test are you running? The test case from this bug report does not reference translate.google.com at all.
Comment 17•5 years ago
•
|
||
Hi Rob,
I'm running the test case from this bug, but I was wrong about the message from comment 15, I just update it.
"Blocked by X-Frame-Options Policy
An error occurred during a connection to www.amazon.com.
Nightly prevented this page from loading in this context because the page has an X-Frame-Options policy that disallows it."
This is the message displayed inside the frame.
Thanks.
Comment 19•5 years ago
|
||
Great, I will update the flags accordingly.
Thank you.
Updated•5 years ago
|
Updated•5 years ago
|
Updated•5 years ago
|
Description
•