Re: Breaking the `opener` relationship.

On Thu, Apr 27, 2017 at 12:57 PM, Mike West <mkwst@google.com> wrote:

> Forking this off and CCing some folks, as it's a sufficiently interesting
> topic on its own.
>
> On Wed, Apr 26, 2017 at 2:28 PM, Artur Janc <aaj@google.com> wrote:
>
>>
>>>>    - I'd love a solution to opener disownership that's generic.
>>>>
>>>> Can you clarify this? I don't understand.
>>>
>>
>> Alex, the CSP3 draft has https://w3c.github.io/webappse
>> c-csp/#directive-disown-opener which might be what you're looking for?
>> FWIW I'd agree with the note in the spec and this bug
>> <https://github.com/w3c/webappsec-csp/issues/194> that this needs some
>> more deliberation.
>>
>
> As noted, I think that `disown-opener` is the wrong thing for a page to
> ask for. Instead, I think something like `block-cross-origin-access-via-windowproxy-and-etc`
> is more accurate. That is, the goal isn't to prevent `window.opener` from
> being set on the protected page. The goal instead is to prevent
> cross-origin pages that gain a reference to the protected page (e.g. via
> `window.open` or `<iframe>` in either direction) to use that reference to
> poke the protected page in ways it might not expect.
>
> Assuming that `https://a.com/sekrit` <https://a.com/sekrit> served a
> response with `content-security-policy: block-cross-origin-access-via-windowproxy-and-etc`,
> I'd expect the following behavior:
>
> 1.  `var x = window.open('https://a.com/sekrit')` <https://a.com/sekrit')>
> executed from `https://evil.com/` <https://evil.com/> would return a
> `WindowProxy` object, just as it does today. But, accessing `x.location` or
> `x.postMessage`, or any of the other cross-origin attributes would throw a
> `SecurityError`.
>
> 2.  Likewise, `var x = window.open('https://evil.com/')`
> <https://evil.com/')> from `https://a.com/sekrit` <https://a.com/sekrit>
> would give `https://evil.com/` <https://evil.com/> a `window.opener`
> handle to `https://a.com/sekrit` <https://a.com/sekrit>, but access would
> throw.
>
> 3.  `https://evil.com/` <https://evil.com/> would be able to reach into
> `<iframe src="https://a.com/sekrit">` via `frame.contentWindow` to get a
> `WindowProxy`, but again we'd block access to the properties/methods.
>
> 4.  Likewise, if `https://a.com/sekrit` <https://a.com/sekrit>
> included `<iframe src="https://evil.com/">`, the latter would gain a
> `window.top` handle to `https://a.com/sekrit` <https://a.com/sekrit>, but
> access would throw.
>

I like the idea in general, but I'm pretty worried about putting #2 and #4
on the same level as #1 and #3. That is, I think it's valuable for pages to
protect themselves from unwanted cross-origin interaction (if they are
opened by an attacker in a new window or frame), but I see less reason to
protect developers from resources they've legitimately decided to embed.
For example, there are many widgets which create cross-origin frames and
communicate with them via postMessage -- if we require restrictions on
embedded content in order to protect our application from a completely
external attacker (#1 and #3) we will prevent adoption in many realistic
scenarios.

It's also worth noting that we have existing mechanisms to protect a page
from potentially malicious frames such as iframe#sandbox and
frame-src/child-src in CSP. One remaining pattern is #2 where we might need
to open external documents in a new window without being able to apply any
of the restrictions we have for frames (some sites currently use proxy
pages to break window.opener for this). To address this use case, maybe we
can separate these two types of restrictions, i.e. have two different
keywords depending on whether we want the restriction to apply when we're
the opener, the openee, or both.


It seems like this would be pretty straightforward to define in HTML (add a
> flag to the settings object, set it via CSP's initialize steps, check it
> somewhere around step 4 of https://html.spec.whatwg.org/#
> windowproxy-getownproperty, throw), though I think Chrome's
> implementation would be complicated. Firefox might have an easier time of
> things given its architecture...
>
> We could, I suppose, even tie this behavior to `window.opener = null` in
> order to cut off access in an imperative way, if that turned out to be
> desirable.
>
> WDYT?
>
> -mike
>

Received on Thursday, 27 April 2017 11:47:25 UTC