Breaking the `opener` relationship.

# Mike West (23 days ago)

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 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](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](https://a.com/sekrit)"> via frame.contentWindow to get a WindowProxy,

but again we'd block access to the properties/methods.

  1. Likewise, if [https://a.com/sekrit](https://a.com/sekrit) included <iframe src=" [https://evil.com/](https://evil.com/)">, the latter would gain a window.top handle to [https://a.com/sekrit](https://a.com/sekrit), but access would throw.

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 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?

Contact us to advertise here
# Artur Janc (23 days ago)

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 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](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) [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)') [https://a.com/sekrit](https://a.com/sekrit)') executed from [https://evil.com/](https://evil.com/) [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/)') [https://evil.com/](https://evil.com/)') from [https://a.com/sekrit](https://a.com/sekrit) [https://a.com/sekrit](https://a.com/sekrit) would give [https://evil.com/](https://evil.com/) [https://evil.com/](https://evil.com/) a window.opener handle to [https://a.com/sekrit](https://a.com/sekrit) [https://a.com/sekrit](https://a.com/sekrit), but access would throw.

  3. [https://evil.com/](https://evil.com/) [https://evil.com/](https://evil.com/) would be able to reach into <iframe src="[https://a.com/sekrit](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) [https://a.com/sekrit](https://a.com/sekrit) included <iframe src="[https://evil.com/](https://evil.com/)">, the latter would gain a window.top handle to [https://a.com/sekrit](https://a.com/sekrit) [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

# Anne van Kesteren (23 days ago)

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

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.

You mean like postMessage()? It would help if we're more explicit about the goals.

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.

That would only work post-navigation, but seems reasonable. What about using window.name to get a reference? Presumably that would fail too?

This would only be for cross-origin? What about similar-origin?

# Devdatta Akhawe (23 days ago)

I am sorry to ask a dumb question but I don't have a lot of context on this: what was the motivation for limiting post message?

I feel like there is chasm between navigating and post messaging. Even though I agree with Artur about risk priority, I am ok with lumping iframe and window.open together for this directive.

But, both for window.open and iframes, I think there is value to allowing post-messages. Post messages have a security model: the target page can check event.origin and ignore the messages; unlike window.opener navigation scenarios. Seconding Artur, I feel like restricting post message will significantly affect ability to effectively adopt this directive.

If we are worried about vulnerabilities in the MessageEvent handlers, I think this is a broader problem and I am all for CSP directives to control who can send/receive post messages from a page.

# Mike West (22 days ago)

Thanks for your comments, folks!

On Thu, Apr 27, 2017 at 4:19 PM, Anne van Kesteren annevk@annevk.nl wrote:

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

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.

You mean like postMessage()? It would help if we're more explicit about the goals.

Dev asked a similar question about the threat model, I'll try to answer both here:

.#2 in wicg.github.io/isolation/#threat of Emily's doc spells out the model in broad strokes. Basically, if someone has a handle to your window, it's not really your window anymore, not fully. Locking down access to w.postMessage(), access to frames (w.length, w.frames['name'], w.frames[1], etc), focus()/blur(), and w.location stand out as the things I'm concerned about. Mostly in the context of Emily's Isolation proposal, but hopefully in a generally applicable way.

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.

That would only work post-navigation, but seems reasonable.

In the initial implementation, yes. In a magical world where Origin Policy was a thing, we might be able to make it work on the intial about:blank as well, since we'd know a priori that the navigation would result in a protected window.

What about using window.name to get a reference? Presumably that would fail too?

If window.name was used to gain a reference to the window, I'd imagine that that reference would be similarly neutered. The flag would need to be available no matter how the proxy object was obtained.

This would only be for cross-origin? What about similar-origin?

WindowProxy's [[GetOwnProperty]] uses html.spec.whatwg.org/#isplatformobjectsameorigin-(-o-): I'd just stick with that as a determinant of the properties listed in html.spec.whatwg.org/#crossoriginproperties-(-o-).

On Fri, Apr 28, 2017 at 4:15 AM, Devdatta Akhawe dev.akhawe@gmail.com wrote: >

Even though I agree with Artur about risk priority, I am ok with lumping iframe and window.open together for this directive.

I think it would be strange to treat these distinctly: both offer third-parties access to your WindowProxy object. It's not clear that trusting one is any different than trusting the other, as they offer the same capabilities.

But, both for window.open and iframes, I think there is value to allowing post-messages. Post messages have a security model: the target page can check event.origin and ignore the messages; unlike window.opener navigation scenarios. Seconding Artur, I feel like restricting post message will significantly affect ability to effectively adopt this directive.

Artur raised similiar concerns. shrug If you do the right thing with source and origin checks, then I agree with you that postMessage() isn't terribly dangerous. That said, we consistently see folks do the wrong thing with these checks. labs.detectify.com/2017/02/28/hacking-slack-using-postmessage-and-websocket-reconnect-to-steal-your-precious-token is the most recent example I can remember of this kind of attack vector.

That said, I recognize the suggestion in both your response and Artur's that blocking all cross-origin access might be overly draconian. I was trying to avoid it, but one of the suggestions that Jonathan Watt made in w3c/webappsec-csp#194 was to turn this into a source list such that the cross-origin check would turn into a list of acceptable origins. I'm a little bit worried about the expense of injecting such an access check into our bindings, but it's an option if a flat lockdown isn't something we can work with. I'm also a little bit worried that you'll next ask for a separation between different types of cross-origin access (e.g. postMessage vs location) which I'm not excited about creating (both because of implementation complexity and developer confusion (where does named-access to frames go, for instance? Or blur()?). "Cross-origin stuff" seems like a narrow enough bucket on its own.

WDYT?

# Anne van Kesteren (22 days ago)

On Fri, Apr 28, 2017 at 10:10 AM, Mike West mkwst@google.com wrote:

WindowProxy's [[GetOwnProperty]] uses html.spec.whatwg.org/#isplatformobjectsameorigin-(-o-): I'd just stick with that as a determinant of the properties listed in html.spec.whatwg.org/#crossoriginproperties-(-o-).

Wouldn't you then fail to address point 7 of the threat model?

# Mike West (22 days ago)

On Fri, Apr 28, 2017 at 10:26 AM, Anne van Kesteren annevk@annevk.nl

wrote:

On Fri, Apr 28, 2017 at 10:10 AM, Mike West mkwst@google.com wrote:

WindowProxy's [[GetOwnProperty]] uses html.spec.whatwg.org/#isplatformobjectsameorigin-(-o-): I'd just stick with that as a determinant of the properties listed in html.spec.whatwg.org/#crossoriginproperties-(-o-).

Wouldn't you then fail to address point 7 of the threat model?

I thought Emily's proposal prevented point 7 by preventing isolated pages from setting document.domain, but I don't see that in the doc. Emily, am I just making things up now? :)

Filed WICG/isolation#12 to discuss, as I'd prefer that approach to increasing the complexity of the WindowProxy checks themselves.

# Anne van Kesteren (22 days ago)

On Fri, Apr 28, 2017 at 10:39 AM, Mike West mkwst@google.com wrote:

Filed WICG/isolation#12 to discuss, as I'd prefer that approach to increasing the complexity of the WindowProxy checks themselves.

Sounds reasonable.

Now, what happens when an isolated document messages with a same-origin document that is not isolated? Is that a risk we care about? If you have a capability-based security model you might hand around ports and assign authority to those ports. However, if these ports are introduced in your system through non-trustworthy pages (per the "people make mistakes" bit of the threat model), is that something we want to protect against? (Could also be a BroadcastChannel that starts emitting propaganda or some such.)

# Mike West (22 days ago)

On Fri, Apr 28, 2017 at 10:55 AM, Anne van Kesteren annevk@annevk.nl

wrote:

On Fri, Apr 28, 2017 at 10:39 AM, Mike West mkwst@google.com wrote:

Filed WICG/isolation#12 to discuss, as I'd prefer that approach to increasing the complexity of the WindowProxy checks themselves.

Sounds reasonable.

Now, what happens when an isolated document messages with a same-origin document that is not isolated? Is that a risk we care about? If you have a capability-based security model you might hand around ports and assign authority to those ports. However, if these ports are introduced in your system through non-trustworthy pages (per the "people make mistakes" bit of the threat model), is that something we want to protect against? (Could also be a BroadcastChannel that starts emitting propaganda or some such.)

This is starting to verge back into the territory of the other thread. In the hopes of keeping separate things separate: for the mechanism we're discussing here, I think it's reasonable to say "Do whatever the existing WindowProxy checks do." If they say do an same origin-domain check, then do a same origin-domain check.

For the broader context, I generally agree with Charlie in lists.w3.org/Archives/Public/public-webappsec/2017Apr/0074.html: I would prefer for it not to be possible for a given origin to be loaded both in an isolated and non-isolated way, both because it's hard to implement and because it's hard to reason about.

If we do end up wanting to load both variants of a page, I think we'd need to hook into the origin model in some way to make them sufficiently dissimilar to fail a same origin-domain check. The isolated flag sketched out in wicg.github.io/isolation/#html-origin might be a reasonable approach.

# Artur Janc (22 days ago)

On Fri, Apr 28, 2017 at 10:10 AM, Mike West mkwst@google.com wrote:

Thanks for your comments, folks!

On Thu, Apr 27, 2017 at 4:19 PM, Anne van Kesteren annevk@annevk.nl wrote:

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

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.

You mean like postMessage()? It would help if we're more explicit about the goals.

Dev asked a similar question about the threat model, I'll try to answer both here:

#2 in wicg.github.io/isolation/#threat of Emily's doc spells out the model in broad strokes. Basically, if someone has a handle to your window, it's not really your window anymore, not fully. Locking down access to w.postMessage(), access to frames (w.length, w.frames['name'], w.frames[1], etc), focus()/blur(), and w.location stand out as the things I'm concerned about. Mostly in the context of Emily's Isolation proposal, but hopefully in a generally applicable way.

A couple of other things: window.stop(), getting load timings from cross-origin frames, and the ability to perform arbitrary CSS/SVG transforms [https://arturjanc.com/xo-frame.html](https://arturjanc.com/xo-frame.html) of cross-origin content, all of which

enabled interesting attacks in the past. I'm not sure if the latter two would be addressed by this proposal, though.

FWIW I also don't think postMessage is a huge concern here given that developers already have a mechanism that lets them decide which messages they trust.

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.

That would only work post-navigation, but seems reasonable.

In the initial implementation, yes. In a magical world where Origin Policy was a thing, we might be able to make it work on the intial about:blank as well, since we'd know a priori that the navigation would result in a protected window.

What about using window.name to get a reference? Presumably that would fail too?

If window.name was used to gain a reference to the window, I'd imagine that that reference would be similarly neutered. The flag would need to be available no matter how the proxy object was obtained.

This would only be for cross-origin? What about similar-origin?

WindowProxy's [[GetOwnProperty]] uses html.spec.whatwg.org# isplatformobjectsameorigin-(-o-): I'd just stick with that as a determinant of the properties listed in html.spec.whatwg. org/#crossoriginproperties-(-o-).

On Fri, Apr 28, 2017 at 4:15 AM, Devdatta Akhawe dev.akhawe@gmail.com wrote: >

Even though I agree with Artur about risk priority, I am ok with lumping iframe and window.open together for this directive.

I think it would be strange to treat these distinctly: both offer third-parties access to your WindowProxy object. It's not clear that trusting one is any different than trusting the other, as they offer the same capabilities.

To clarify, I don't think we should treat window.open and iframes differently, but that we should distinguish restrictions based on whether (1) the document is being embedded/opened by external content, and (2) the document itself decides to embed/open external content. I can see a lot of benefit to (1) and would use it in many applications; I don't see much benefit to (2) over existing mechanisms, and suspect it might make it less deployable if we bundle these two types of restrictions.

But, both for window.open and iframes, I think there is value to allowing post-messages. Post messages have a security model: the target page can check event.origin and ignore the messages; unlike window.opener navigation scenarios. Seconding Artur, I feel like restricting post message will significantly affect ability to effectively adopt this directive.

Artur raised similiar concerns. shrug If you do the right thing with source and origin checks, then I agree with you that postMessage() isn't terribly dangerous. That said, we consistently see folks do the wrong thing with these checks. labs.detectify.com/2017/02/28 hacking-slack-using-postmessage-and-websocket-reconnect-to-steal-your- precious-token/ is the most recent example I can remember of this kind of attack vector.

That said, I recognize the suggestion in both your response and Artur's that blocking all cross-origin access might be overly draconian. I was trying to avoid it, but one of the suggestions that Jonathan Watt made in w3c/webappsec-csp#194 was to turn this into a source list such that the cross-origin check would turn into a list of acceptable origins. I'm a little bit worried about the expense of injecting such an access check into our bindings, but it's an option if a flat lockdown isn't something we can work with. I'm also a little bit worried that you'll next ask for a separation between different types of cross-origin access (e.g. postMessage vs location) which I'm not excited about creating (both because of implementation complexity and developer confusion (where does named-access to frames go, for instance? Or blur()?). "Cross-origin stuff" seems like a narrow enough bucket on its own.

WDYT?

I'm perfectly happy with a flat lockdown if we can apply it to case (1) but not (2) ;-)

# Emily Stark (22 days ago)

On Fri, Apr 28, 2017 at 1:39 AM, Mike West mkwst@google.com wrote:

On Fri, Apr 28, 2017 at 10:26 AM, Anne van Kesteren annevk@annevk.nl wrote:

On Fri, Apr 28, 2017 at 10:10 AM, Mike West mkwst@google.com wrote:

WindowProxy's [[GetOwnProperty]] uses html.spec.whatwg.org/#isplatformobjectsameorigin-(-o-): I'd just stick with that as a determinant of the properties listed in html.spec.whatwg.org/#crossoriginproperties-(-o-).

Wouldn't you then fail to address point 7 of the threat model?

I thought Emily's proposal prevented point 7 by preventing isolated pages from setting document.domain, but I don't see that in the doc. Emily, am I just making things up now? :)

Filed WICG/isolation#12 to discuss, as I'd prefer that approach to increasing the complexity of the WindowProxy checks themselves.

You're right, it's supposed to turn off document.domain but I hadn't gotten around to it yet (WICG/isolation#3)

# Mike West (22 days ago)

On Fri, Apr 28, 2017 at 2:12 PM, Artur Janc aaj@google.com wrote:

#2 in wicg.github.io/isolation/#threat of Emily's doc spells out

the model in broad strokes. Basically, if someone has a handle to your window, it's not really your window anymore, not fully. Locking down access to w.postMessage(), access to frames (w.length, w.frames['name'], w.frames[1], etc), focus()/blur(), and w.location stand out as the things I'm concerned about. Mostly in the context of Emily's Isolation proposal, but hopefully in a generally applicable way.

A couple of other things: window.stop()

I don't think this is exposed cross-origin today.

getting load timings from cross-origin frames, and the ability to perform arbitrary CSS/SVG transforms [https://arturjanc.com/xo-frame.html](https://arturjanc.com/xo-frame.html) of cross-origin content, all of which enabled interesting attacks in the past. I'm not sure if the latter two would be addressed by this proposal, though.

They would not. At the moment, I'm strictly considering things that hang off the WindowProxy object. The vectors you mention here both seem like interesting things to defend against, but somewhat distinct from what I'm suggesting. Do you see them as intertwined-enough to justify tying them together?

FWIW I also don't think postMessage is a huge concern here given that

developers already have a mechanism that lets them decide which messages they trust.

I agree with you that it should be straightforward to defend against postMessage-based attacks. As noted elsewhere, however, the postMessage API is pretty easy to get wrong, and has lead to practical attacks in the past. Maybe Google's doing a better job with this internally than other folks?

On Fri, Apr 28, 2017 at 4:15 AM, Devdatta Akhawe dev.akhawe@gmail.com

wrote: >

Even though I agree with Artur about risk priority, I am ok with lumping iframe and window.open together for this directive.

I think it would be strange to treat these distinctly: both offer third-parties access to your WindowProxy object. It's not clear that trusting one is any different than trusting the other, as they offer the same capabilities.

To clarify, I don't think we should treat window.open and iframes differently, but that we should distinguish restrictions based on whether (1) the document is being embedded/opened by external content, and (2) the document itself decides to embed/open external content. I can see a lot of benefit to (1) and would use it in many applications; I don't see much benefit to (2) over existing mechanisms, and suspect it might make it less deployable if we bundle these two types of restrictions.

There's a practical challenge here, in that the WindowProxy checks don't currently have any notion of how one window got access to another.

I'm sure we could wire it through somehow, so let's assume we could make the distinction. In general, a.com framing b.com does seem like an indication that a.com trusts b.com to some extent. I'm not sure the same can be said for opening b.com in a new window. In fact, most of the time I see new-window navigations, the opposite is the intent (e.g. "We have nothing to do with this page, we just think it might be interesting to you. Please come back to us when you're done? Please?").

And, really, one of the wonderful things about iframe is that it separates out a chunk of content on the page. I'll bet that there are folks out there (maybe even on this list!) that use frames for isolation because they don't actually trust the content they're loading. Look at the old implementation of images.google.com, for instance, which framed the destination page for context.

But, both for window.open and iframes, I think there is value to

allowing post-messages. Post messages have a security model: the target page can check event.origin and ignore the messages; unlike window.opener navigation scenarios. Seconding Artur, I feel like restricting post message will significantly affect ability to effectively adopt this directive.

Artur raised similiar concerns. shrug If you do the right thing with source and origin checks, then I agree with you that postMessage() isn't terribly dangerous. That said, we consistently see folks do the wrong thing with these checks. labs.detectify.com/2017/02/28/hacking-slack- using-postmessage-and-websocket-reconnect-to-steal-your-precious-token/ is the most recent example I can remember of this kind of attack vector.

That said, I recognize the suggestion in both your response and Artur's that blocking all cross-origin access might be overly draconian. I was trying to avoid it, but one of the suggestions that Jonathan Watt made in w3c/webappsec-csp#194 was to turn this into a source list such that the cross-origin check would turn into a list of acceptable origins. I'm a little bit worried about the expense of injecting such an access check into our bindings, but it's an option if a flat lockdown isn't something we can work with. I'm also a little bit worried that you'll next ask for a separation between different types of cross-origin access (e.g. postMessage vs location) which I'm not excited about creating (both because of implementation complexity and developer confusion (where does named-access to frames go, for instance? Or blur()?). "Cross-origin stuff" seems like a narrow enough bucket on its own.

WDYT?

I'm perfectly happy with a flat lockdown if we can apply it to case (1) but not (2) ;-)

Can you talk about the use cases you'd have for Google properties? If you could have unicorns and ponies, what would user agents be doing for you with regard to properties on window handles?

# Artur Janc (22 days ago)

On Fri, Apr 28, 2017 at 4:24 PM, Mike West mkwst@google.com wrote:

On Fri, Apr 28, 2017 at 2:12 PM, Artur Janc aaj@google.com wrote:

#2 in wicg.github.io/isolation/#threat of Emily's doc spells out

the model in broad strokes. Basically, if someone has a handle to your window, it's not really your window anymore, not fully. Locking down access to w.postMessage(), access to frames (w.length, w.frames['name'], w.frames[1], etc), focus()/blur(), and w.location stand out as the things I'm concerned about. Mostly in the context of Emily's Isolation proposal, but hopefully in a generally applicable way.

A couple of other things: window.stop()

I don't think this is exposed cross-origin today.

You're right; I meant the fact that window.stop() on the embedder affects the state of cross-origin frames, and it would nice if it didn't, but it's minor point and probably not worth dwelling on ;)

getting load timings from cross-origin frames, and the ability to perform arbitrary

CSS/SVG transforms [https://arturjanc.com/xo-frame.html](https://arturjanc.com/xo-frame.html) of cross-origin content, all of which enabled interesting attacks in the past. I'm not sure if the latter two would be addressed by this proposal, though.

They would not. At the moment, I'm strictly considering things that hang off the WindowProxy object. The vectors you mention here both seem like interesting things to defend against, but somewhat distinct from what I'm suggesting. Do you see them as intertwined-enough to justify tying them together?

FWIW I also don't think postMessage is a huge concern here given that

developers already have a mechanism that lets them decide which messages they trust.

I agree with you that it should be straightforward to defend against postMessage-based attacks. As noted elsewhere, however, the postMessage API is pretty easy to get wrong, and has lead to practical attacks in the past. Maybe Google's doing a better job with this internally than other folks?

Nice try, but I don't think so ;-)

In general, I see most of the value of the proposed opener restrictions in breaking access to the DOM properties you mentioned (assigning to window.location, traversing frames, etc). I see some value in trying to disable other shenanigans which leak or change state across origins like the ones I mentioned earlier, especially if there's going to be an explicit flag that indicates the document wants to protect itself from cross-origin interaction; but I won't be very sad if that doesn't happen, especially X-Frame-Options already helps protect against some of this.

I'm mostly indifferent about postMessage because I doubt that developers who don't properly perform the one crucial security check that postMessage requires will clamor to adopt a new feature which requires more testing (than just checking event.origin), and which can't be easily set by their JS framework (unlike postMessage wrappers which can do origin checks by default).

But just to be clear, I don't have any problem with breaking postMessage to our document if we're being opened or iframed across origins. I just don't want to have to -- at the same time -- block our document from talking to iframes and widgets that we've explicitly embedded because that has little security upside and a large compatibility downside.

On Fri, Apr 28, 2017 at 4:15 AM, Devdatta Akhawe dev.akhawe@gmail.com

wrote: >

Even though I agree with Artur about risk priority, I am ok with lumping iframe and window.open together for this directive.

I think it would be strange to treat these distinctly: both offer third-parties access to your WindowProxy object. It's not clear that trusting one is any different than trusting the other, as they offer the same capabilities.

To clarify, I don't think we should treat window.open and iframes differently, but that we should distinguish restrictions based on whether (1) the document is being embedded/opened by external content, and (2) the document itself decides to embed/open external content. I can see a lot of benefit to (1) and would use it in many applications; I don't see much benefit to (2) over existing mechanisms, and suspect it might make it less deployable if we bundle these two types of restrictions.

There's a practical challenge here, in that the WindowProxy checks don't currently have any notion of how one window got access to another.

I'm sure we could wire it through somehow, so let's assume we could make the distinction. In general, a.com framing b.com does seem like an indication that a.com trusts b.com to some extent. I'm not sure the same can be said for opening b.com in a new window. In fact, most of the time I see new-window navigations, the opposite is the intent (e.g. "We have nothing to do with this page, we just think it might be interesting to you. Please come back to us when you're done? Please?").

How would an attack work in this case? It seems like an attacker would need to persistently compromise an origin we link to, wait until the user opens the new window, then use that window to get a handle to us and attack us by sending a postMessage, setting location.hash or something like that (assuming our app has a vulnerability there). There might certainly be cases where an application wants to protect against this (and can do so with an opener-breaking proxy page) but I'd guess that it's a couple of orders of magnitude less frequent than the situations where we or our widgets legitimately want to communicate with embedded cross-origin content.

And, really, one of the wonderful things about iframe is that it separates out a chunk of content on the page. I'll bet that there are folks out there (maybe even on this list!) that use frames for isolation because they don't actually trust the content they're loading. Look at the old implementation of images.google.com, for instance, which framed the destination page for context.

But, both for window.open and iframes, I think there is value to

allowing post-messages. Post messages have a security model: the target page can check event.origin and ignore the messages; unlike window.opener navigation scenarios. Seconding Artur, I feel like restricting post message will significantly affect ability to effectively adopt this directive.

Artur raised similiar concerns. shrug If you do the right thing with source and origin checks, then I agree with you that postMessage() isn't terribly dangerous. That said, we consistently see folks do the wrong thing with these checks. labs.detectify.com/2017/02/28/hacking-slack- using-postmessage-and-websocket-reconnect-to-steal-your-precious-token/ is the most recent example I can remember of this kind of attack vector.

That said, I recognize the suggestion in both your response and Artur's that blocking all cross-origin access might be overly draconian. I was trying to avoid it, but one of the suggestions that Jonathan Watt made in w3c/webappsec-csp#194 was to turn this into a source list such that the cross-origin check would turn into a list of acceptable origins. I'm a little bit worried about the expense of injecting such an access check into our bindings, but it's an option if a flat lockdown isn't something we can work with. I'm also a little bit worried that you'll next ask for a separation between different types of cross-origin access (e.g. postMessage vs location) which I'm not excited about creating (both because of implementation complexity and developer confusion (where does named-access to frames go, for instance? Or blur()?). "Cross-origin stuff" seems like a narrow enough bucket on its own.

WDYT?

I'm perfectly happy with a flat lockdown if we can apply it to case (1) but not (2) ;-)

Can you talk about the use cases you'd have for Google properties? If you could have unicorns and ponies, what would user agents be doing for you with regard to properties on window handles?

I like the idea of breaking interaction with our applications by arbitrary third parties who embed us or open us in a new window. It seems like a useful defense in depth against some creative attacks which are perhaps not super frequent or damaging, but kind annoying (tabnabbing, XSS filter infoleaks based on frame counting, and even the occasional postMessage-based XSS!) I believe most applications could use this and it could be a lightweight way to get some isolation for apps which can't be in Isolated Origins.

I do not like the idea of combining this benefit with a requirement to break access to our document from content we iframe because then we couldn't use it (but I see no problem if it's enabled via a separate flag).

# Devdatta Akhawe (19 days ago)

First, I agree with Artur, re his concern on iframes being treated same as new windows. I figured if its easier conceptually or for UA implementation, I am ok with it. Especially, if we allow x-origin postMessage.

Re the postMessage threats flagged: I haven't dug deep into the Slack bug (asking Frans on the side) but I suspect that the reason for using postMessage was to allow cross-origin communications. If my hypothesis is right, blocking all postMessage means that they can't adopt this proposal.

The class of issues flagged by Frans has been discussed for a long time. I think a distinction between the opener bugs and postMessage bugs is that with postMessage you need to opt-in: you need to add an event listener. And there is a way to secure it: check the origin of the event. There is no such 'localized' option for opener bugs.

You are absolutely right that this is an area where people make mistakes, but the current proposal won't solve this bug for people who actually need to use postMessage cross-origin. Worse, it will mean that people who need to make cross-origin postMessages can't adopt this proposal. For example, if a page opens two popups: one untrusted and one trusted it wants to communicate with, it won't be able to adopt this proposal.

I am all for a separate CSP directive to control postMessage send/receive; I think that will be very useful for a large class of web applications.

(I am biased: when our team worked on such postMessage issues back in 2010 [http://devd.me/papers/w2sp10-primitives.pdf](http://devd.me/papers/w2sp10-primitives.pdf), even then we argued for post

message controls in CSP.)

Want more features?

Request early access to our private beta of readable email premium.