Open jakemco opened 6 years ago
See https://github.com/whatwg/html/issues/3740 for a proposal to limit this to some extent.
See also #1509 for a similar issue.
For anyone else momentarily confused, remember that window.frames === window
, so this is not something frames-related, it's just how windows work.
window.frames
can reveal information about sites in a different origin, providing a side channel to break the same origin policy.Description
Given two sites, site A and site B. Assume site B has a page where it renders an iframe for each instance of some content. For the purposes of this example, that iframe can be to another page on site B or to a third site. Site A can render a pop-up or an iframe to site B, retrieve a handle to the window, and get back the number of frames via
otherWindow.frames.length
. The number of pieces of content for a particular user on this page could be sensitive (comments, messages, search results, etc.), or even the existence of frames on the page could be a side channel (an iframe only rendered on a particular page for users with a specific role on that site), and so this api is therefore exposing a cross-origin side channel for that information.Site A is also able to change the location of the iframes rendered in site B by calling
otherWindow.frames[n].location.replace('...')
. In this way, an attacker could change the content of a displayed iframe to display alternate information, or change the target of a*
target origin postMessage (which is problematic to begin with, but closing this hole closes that hole).Example:
This example uses iframes because it was quick to write, but it could just as easily use pop-ups (open a link with target
_blank
and get a window handle) to bypass XFO.site-a/index.html:
site-b/index.html:
running site-a as
localhost:8080
and site-b aslocalhost:8081
, eg:python3 -m http.server 808{0,1}
In this example,
n
is clearly not sensitive as it's a url parameter that site-a chose, but it could just as easily be based on a cookie value or other sensitive data that site-a should not be able to retrieve.In the js console of site-a you can also do
document.getElementById('target').contentWindow.frames[0].location.replace('http://some-other-site')
to manipulate the iframe from another origin.Note: this also works with
window.length
,window[0]
, etc.Suggested Solution
Either prevent sites from accessing cross-origin frames at all, or limit them to accessing cross-origin frames that point back into their own origin, eg: a site-b with two iframes, one that points to site-b and one that points to site-a would return a window.frames.length of 1 when called from site-a.