Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Making postMessage() work for SharedArrayBuffer (Cross-Origin-Embedder-Policy) #4175

Open
annevk opened this issue Nov 14, 2018 · 92 comments

Comments

@annevk
Copy link
Member

commented Nov 14, 2018

#3740 (comment) sketches out v1 for the various headers needed to enable SharedArrayBuffer and friends.

At Mozilla we think we'll quickly need to address a need @arturjanc and @csreis hinted at. Being able to have cross-origin frames, either in the same process (e.g., because it's a process-contrained environment), or in a different process.

Our idea around this would be to add a new keyword to the Cross-Origin-Frame-Policy header:

Cross-Origin-Frame-Policy: same cors
Cross-Origin-Frame-Policy: same-site cors

If the cors keyword isn't set the v1 semantics apply, and cross-origin/site navigations result in a network error. If the cors keyword is set, the CORS protocol semantics apply to frame navigations. Judging from https://wicg.github.io/cors-rfc1918/ this could mostly be done through modifications to Fetch, which makes this less difficult than I initially anticipated. Navigations should also never require a preflight, therefore only requiring modifications to the final resource on servers (and redirects, if any).

A risk here for the embedder is that the embedded could redirect or navigate to an attacker. https://w3c.github.io/webappsec-cspee/ and sandboxing can be used to mitigate this, similar to how you'd combat XSS in your own document.

The short term advantage is that we could have something that works in all browsers more quickly, the long term advantage would be potentially saving on resource usage. And more speculatively this kind of trust relationship might also be beneficial to other APIs.

We'd like to implement this shortly after or together with v1.

Note that none of this has an effect on the WindowProxy/Location same origin-domain check. That will continue to consider such frames as being in a different origin.

cc @whatwg/security @rniwa @tomrittervg

@csreis

This comment has been minimized.

Copy link

commented Nov 15, 2018

Thanks for proposing this! If I follow correctly, this would basically allow SharedArrayBuffer-enabled documents to load cross-origin iframes as long as the iframe requests use CORS (in the spirit of X-Bikeshed-Allow-Unisolated-Embed). This would imply that the cross-origin iframe's server would acknowledge that such data would be accessible to the embedding page, and thus it's safe to include in the same process even if SharedArrayBuffers or other precise time features make Spectre attacks more likely. (Meanwhile, browsers with support for cross-process frames could load such iframes in a different process without diverging in behavior from the user's perspective.)

I'm not 100% sure ad sites (etc) would go for this "full access" approach (where the embedding page could just as easily fetch the iframe URL and read its contents), but it does seem to make explicit that the data could be read with Spectre, and thus conveys the risks in a reasonable way. I imagine it might be sufficient.

I think this would resolve my main concern from the other thread (#3740 (comment)). @arturjanc, does this sound reasonable from your perspective?

@mikewest

This comment has been minimized.

Copy link
Member

commented Nov 15, 2018

Navigations should also never require a preflight, therefore only requiring modifications to the final resource on servers (and redirects, if any).

For my own clarity, I think this is what you're proposing:

  1. The embedding document asserts Cross-Origin-Frame-Policy: cors.
  2. The embedding document embeds <iframe src="https://cross-origin.site/">.
  3. The browser requests https://cross-origin.site/, sending an Origin and
  4. If https://cross-origin.thing/ responds with Access-Control-Allow-Origin: https://embedder.site/ and Access-Control-Allow-Credentials: true, we allow the embedding. Otherwise, we return a network error.

Is that right?

It's not clear to me what capabilities this would expose. Like, does the embedder get DOM access to the embedee? That seems like something we'd want to avoid. As @csreis notes, this also seems to create the risk that page contents are directly revealed via fetch(), which also seems like something we'd want to avoid.

CORS-RFC1918 took a different approach, forcing a preflight, but not forcing CORS access to the page itself. That might be an interesting approach here as well, as it would reduce the risk that page content would be inadvertently exposed to an embedder by making it opt-in (via the preflight response), but not directly exposing the page data to the embedder (by not requiring CORS headers on the non-preflight response itself).

@annevk

This comment has been minimized.

Copy link
Member Author

commented Nov 15, 2018

It's not clear to me what capabilities this would expose.

It mainly would allow for process reuse on process-constrained environments, as stated in OP.

Like, does the embedder get DOM access to the embedee?

See last paragraph of OP.

As @csreis notes, this also seems to create the risk that page contents are directly revealed via fetch()

It's not clear to me how much it's worth trying to distinguish that case from putting something in the same process. It seems it might give a false sense of security.

@arturjanc

This comment has been minimized.

Copy link

commented Nov 19, 2018

For opt-in, I like @mikewest's preflight-based approach from https://wicg.github.io/cors-rfc1918/#shortlinks

This should allow the owners of cross-origin resources to respond to OPTIONS requests with something like Access-Control-Allow-Embed: true without also allowing direct reads of response contents via fetch(). I sympathize with the concern about giving server owners a false sense of security, but would prefer to avoid encouraging server owners to allow direct access to their responses (e.g. we don't want ad network resources to be directly readable via CORS since that would reveal interesting information about users).

There is a possibility that Spectre-like attacks would be able to exfiltrate the contents of the frame, but they would likely be less powerful and noisy; and, importantly, they wouldn't work against browsers with OOPIFs (whereas if we require regular CORS opt-in via Access-Control-Allow-Origin then we would expose the contents also in browsers with OOPIFs where introducing the leak isn't necessary.)

A benefit of this approach is that it would enable identical behavior across browsers: on pages with Cross-Origin-Frame-Policy all browsers would send a preflight on cross-origin iframe requests and would require the server to opt in. However, as browsers adopt OOPIFs the responses would become safe against exfiltration via speculative execution attacks, while still requiring the server to opt into embedding (which is okay because servers will have to do this in the short term anyway).

@arturjanc

This comment has been minimized.

Copy link

commented Nov 19, 2018

Also, stepping back a bit, do we even need the same / same-site switch in this case? I think we can allow same-origin frames by default, and for any non-same-origin framing requests we could use the CORS / preflight approach to require resource owners to opt in. This would also be safer because we would prevent foo.example.org from declaring itself eligible to frame bar.example.org while getting access to high-res timers or other dangerous APIs, allowing it to potentially exfiltrate cross-origin contents from its sibling subdomain.

If we did this, then the header could just become Cross-Origin-Frame-Policy: 1 (or some other more descriptive name/value.)

Also, to push this idea as far as possible, could we even completely fold this into the Upgrade-No-CORS header? Then the header would require sending all non-same-origin subresource requests as CORS and do the same for iframes as discussed above. It would also have to apply recursively to all frames, but this should be okay because, as outlined above, servers would have to opt in or otherwise the frame would not be loaded.

I think this might be conceptually simpler for developers while giving us all the security properties we need for the L2 mechanism.

@annevk

This comment has been minimized.

Copy link
Member Author

commented Nov 20, 2018

  1. If you don't do "true" CORS for navigations, I don't think it's reasonable for browsers to same-process these frames long term. That might be okay, but wouldn't be ideal for process-contrained environments.
  2. Upgrade-No-CORS is specifically named after Fetch's "no-cors" mode. Navigations use the "navigate" mode, which is similar, but different. Also, per your proposal navigations wouldn't use "true" CORS, they'd only preflight.

So I think I agree with your plan, but we need a new name for the header. Perhaps Use-CORS, with the explanation that for subframe navigations this means a specific kind of preflight only.

So, why not also use this approach for popups you want to cooperate with?

@annevk

This comment has been minimized.

Copy link
Member Author

commented Nov 23, 2018

So while trying to explain this model to someone over lunch I realized this allows for escaping the "Use-CORS" restriction in browsers without process-isolated frames/popups.

attacker.example specifies Use-CORS and the correct opener policy. It loads collaborator.attacker.example in a frame/popup and that positively replies to the preflight. collaborator.attacker.example isn't restricted itself by CORS however can load all kinds of "no-cors" resources into the process.

It seems to me we need to require that collaborator.attacker.example also specifies Use-CORS.

@annevk

This comment has been minimized.

Copy link
Member Author

commented Nov 23, 2018

I talked with @arturjanc, his assumption was that Use-CORS is inherited cross-origin in these cases, which is probably acceptable as the navigation response opted into it via the preflight.

@annevk

This comment has been minimized.

Copy link
Member Author

commented Nov 23, 2018

Not discussed yet: if you restrict to same-origin, what are the implications for document.domain (also raised at #3740 (comment)) and SharedArrayBuffer? It seems those would not work then cross-origin, but same-site. It's not entirely clear to me if that's desirable. (It's ideal, but...)

@annevk

This comment has been minimized.

Copy link
Member Author

commented Jan 4, 2019

I'm no longer entirely convinced we need the preflight.

  1. I'm worried it creates an unacceptable performance penalty.
  2. It doesn't seem to offer any additional protection. It was inspired by the local network proposal where it does make sense, but CSRF will remain a problem here and has to be dealt with differently.

I think instead the model should be such that once a browsing context group has its "Use-CORS" flag set, any resource navigated to within that group needs to have the Use-CORS header set. And if not, the network layer will return a network error. I'm not entirely sure if we should require redirects to have this header set or not. (A redirect can be navigated to if it doesn't have a Location header or the value of that header cannot be parsed. In that particular case it definitely needs to have the header set, but I'm less clear on when we simply follow it to somewhere else.)

Then, there's the question of credentials. Other than with fetch() (which defaults to "same-origin" for credentials), "no-cors" fetches will always include credentials across origins. So we need to at least support the equivalent of HTML's crossorigin="use-credentials" (this made me think that Cross-Origin: use-credentials as header might not be too bad). Whether we also need crossorigin="anonymous" is less clear, but that would allow for a less complicated CORS setup.

If we allow variance in credentials, it probably does not make sense to require it to match across documents. It's reasonable for different documents (esp. cross-origin) to have their own "no-cors" credentials policy.


For a moment I was worried about service workers and the cache API being able to introduce opaque responses into "Use-CORS" documents. However, this concern is probably unfounded. A service worker is handled by it not being able to return opaque responses to "cors" fetches (we'll upgrade before hitting the service worker). The cache API will need to be restricted from returning opaque responses in "Use-CORS" environments somehow. Currently you cannot do anything with such responses anyway in documents so maybe that's enough (assuming an implementation that leaves the bytes in the "storage process" until requested), but we'll need to be cautious going forward. An alternative is to prevent them from being returned altogether when the top-level flag is set.

@annevk

This comment has been minimized.

Copy link
Member Author

commented Jan 4, 2019

When does Use-CORS/Cross-Origin take effect:

  1. It initially needs to be a on a resource that results in the creation of a new browsing context group. I.e., one that has Cross-Origin-Opener-Policy set.
  2. To be clear, this Cross-Origin-Opener-Policy requirement doesn't apply to further navigated resources loaded in that browsing context group. For those only this new second header matters (except for top-level browsing context navigations with a non-matching Cross-Origin-Opener-Policy).

As for document.domain:

  1. The simplest thing to do I think is to continue to allow document.domain and to continue to key agent clusters on sites. Same-site resources can only be attacked if they opt in via CORS or this new second header though (assuming they're navigable).
  2. The ambitious thing to do is to require Cross-Origin-Opener-Policy: same-origin ... when using this new second header and change the browsing context group's agent cluster keying such that the key is now origin, effectively disabling document.domain. Unless folks are particularly motivated to do this exercise, this seems unlikely to happen. Attempts at making document.domain worse in the past have largely failed and tightly coupling the worsening with important new features puts the new feature at risk.
@annevk

This comment has been minimized.

Copy link
Member Author

commented Jan 8, 2019

A thing we haven't really discussed or at least written down in these threads is how SharedArrayBuffer is enabled. I propose that SharedArrayBuffer is always there, but only agent clusters with a flag set allow it to be messaged between agents. This means that the ECMAScript standard can continue to say it's always exposed and HTML (the host) will impose the limitation on usage. By not allowing it to be messaged it's effectively equivalent to and no more dangerous than ArrayBuffer.

Making StructuredSerializeInternal throw ("DataCloneError") when it's invoked in an agent cluster that wasn't created under the right circumstances should be sufficient for this I think.

@annevk annevk changed the title Cross-Origin-Frame-Policy v2, enabling cross-origin frames Opting into a CORS-only mode (Cross-Origin) Jan 18, 2019

@annevk

This comment has been minimized.

Copy link
Member Author

commented Jan 18, 2019

Feedback and attempts to address it:

  • How do sites know about being included? I think we should reuse the Origin header here. This already works for CORS, it seems fine to reuse here. As Origin is used for CORS purposes, Referrer Policy cannot affect it (for subframe and popup navigations). Currently Origin is not included for GET navigations, so this should work I think (and server-side needs changes anyway due to the response headers).
  • Should we require X-Frame-Options? This was suggested as Cross-Origin would be used for all responses so if you don't consider the possibility of being framed, someone might end up framing you. It seems somewhat reasonable, but I'm a little wary of adding this additional complexity. (Remember that currently Chrome requires none of this.) We don't have to add allow from * necessarily as you could echo the origin value after allow-from (similar to what we require with CORS). Potential issues:
    • same-origin is spelled sameorigin (case-insensitive too) and there's no same-site as we have elsewhere.
    • There's an equivalent feature in CSP. Would we also make that work and increase the complexity even more? I'd hope not.
    • I think there are some interoperability issues around allow-from.
  • Does Cross-Origin work in a browsing context group without Cross-Origin-Opener-Policy? Nika argued that it should and apply to the subtree. I think that's fine. We do have to be careful here with what other APIs build on top of this as this isn't necessarily a secure primitive (i.e., nothing should prolly be build on top of this). It would mainly give consistency in loading resources.
@annevk

This comment was marked as off-topic.

Copy link
Member Author

commented Jan 25, 2019

While working on #4284 I realized that non-auxiliary top-level browsing contexts can also get assigned external state:

  • A name, even when noopener is used. I think if Cross-Origin-Opener-Policy is specified we should get rid of the name. This has no negative consequences that I can think of. The site itself can still set it.
  • Sandboxing flags. We cannot get rid of these as it would allow for escaping the sandbox. So either we allow and apply them, or we "network error" the browsing context. Allowing and applying them seems reasonable, given that it's the status quo, but we could consider some kind of flag that makes sandboxing result in a network error, rather than a response that, e.g., cannot execute script or has a opaque origin. (The scenario to get here is A being sandboxed with "allow-popups" and opening B. If B has Cross-Origin-Opener-Policy set we run into this.)
@annevk

This comment was marked as off-topic.

Copy link
Member Author

commented Jan 28, 2019

So, given that inheriting sandboxing flags is such a niche case (can only happen when opening a popup from a sandboxed frame with allow-popups), I think we should instead network error in that case, such that when you create a new browsing context group it always starts out without external state. That seems like a much safer long term design. (If this turns out to be prohibitive for some unlikely reason we can always stop returning a network error at that point and inherit the sandbox flags after all.)

@csreis

This comment was marked as resolved.

Copy link

commented Jan 29, 2019

Just to clarify, are the name and sandboxing flags comments mainly about Cross-Origin-Opener-Policy (#3740) and not Cross-Origin? I didn't see a Cross-Origin connection to them at first glance.

I'm not opposed to clearing the name when we do a replacement. Chrome scopes names to the browsing context group anyway, and it seems reasonable not to import an old name when we create a new browsing context group.

I'm also ok with an error in the sandboxing flags case, with the potential to relax that later if it interferes with sites in practice.

@jakearchibald

This comment has been minimized.

Copy link
Collaborator

commented Feb 8, 2019

Can a Use-CORS page contain an iframe to a cross-origin page that doesn't have Use-CORS? What happens if a SharedArrayBuffer is postMessaged to the iframe?

Update: BroadcastChannel and the service worker clients API creates the same problem with same-origin pages.

@annevk

This comment has been minimized.

Copy link
Member Author

commented Feb 9, 2019

https://gist.github.com/annevk/17f580379c45802d5c3aef5a8fd53c7d has more details on the processing model. Feedback welcome!

@jakearchibald the iframe case would result in a network error for the frame. BroadcastChannel does not pose a problem as those pages would be in different agent clusters (they'd get the messageerror event). Service workers are also in their own agent cluster.

@clelland

This comment has been minimized.

Copy link
Contributor

commented Feb 21, 2019

Edit: Updated link

I'm wondering if it would be possible to extend this with a mode which simply set all fetch requests' credentials modes to 'omit', without also upgrading to CORS?

Cross-Origin: omit

This could allow sites to adopt the Cross-Origin header to enforce that they do not ever request any user-specific data from third parties, but would still be able to link to anonymous public resources, cache images and scripts on CDNs, and preserve the more-or-less free embedding that the web has always had.

I had written up a proposal along those lines here a few days ago, which seems very similar in spirit to this.

@csreis

This comment has been minimized.

Copy link

commented Feb 22, 2019

Thanks for mentioning, @clelland! I think the credential-less mode is worth considering, as it would allow sites to pull in effectively public third party subresources without needing CORS on them, and thus impose fewer restrictions without giving up much of the security value. (Presumably documents could optionally request credentialed subresources with CORS if they wanted them.) I also imagine that would be easier to eventually enable by default than CORS-only, and using it here for enabling precise timers might be a step in that direction.

The main hole is probably intranet resources, but maybe something like RFC1918 can help (cc @mikewest)?

What are others' thoughts on full CORS vs credential-less requests?

@csreis

This comment has been minimized.

Copy link

commented Feb 22, 2019

Adding @bzbarsky and @ehsan, who brought up similar ideas about a credential-less mode (or default) in the past. Requiring it to enable precise time (perhaps instead of CORS for all cross-site subresources, as we've been discussing here?) might be a nice step towards making credential-less subresources be the default, which would help cover the cases CORB misses today.

@arturjanc

This comment has been minimized.

Copy link

commented Jun 14, 2019

e.g. IIUC it would prevent creating new windows to non-CORP-P resources, even when they don't need to directly interact with the opener and could be safely put in a new browsing context group by COOP.

I don't understand this part. The only "blocking" behavior in my previous comment is 1., which is only applicable to nested frames, but this seems not related to nested frames.

Apologies, I think I misunderstood your point (1) -- I thought the idea was to prevent auxiliary browsing contexts opened by a window with CORP-P from being put in the same browsing context group (to protect them). If this applies only to frames, that should be fine, but which part of your proposal handles the auxiliary browsing context case? Does "navigate" in (2) and (3) also imply opening new auxiliary contexts and navigating them?

One other thing that I wasn't clear on are cross-origin CORP-P to CORP-P navigations: I expect these would also have to create a new browsing context group because we don't want a cross-origin link to allow the target to read the contents of memory from the original CORP-P page. (This is related to my original concern that without an integration with COOP, CORP-P would need to independently solve similar problems to what COOP aims to address.)

I'm fine with this, but in that case wouldn't the name COOP be misleading?

The name is already somewhat inaccurate because it also governs same-origin interactions (e.g. it can put same-origin pages in different browsing context groups if one has COOP), but it's also hard to come up with a less misleading one... I defer to @annevk on this, though I don't think the current name is particularly bad.

@yutakahirano

This comment has been minimized.

Copy link
Member

commented Jun 17, 2019

If this applies only to frames, that should be fine, but which part of your proposal handles the auxiliary browsing context case? Does "navigate" in (2) and (3) also imply opening new auxiliary contexts and navigating them?

(2) and (3) include that. (2) and (3) include usual navigations, too.

One other thing that I wasn't clear on are cross-origin CORP-P to CORP-P navigations: I expect these would also have to create a new browsing context group because we don't want a cross-origin link to allow the target to read the contents of memory from the original CORP-P page. (This is related to my original concern that without an integration with COOP, CORP-P would need to independently solve similar problems to what COOP aims to address.)

I was thinking about

  1. Having a dedicated HTTP header for CORP-P,
  2. Having a unified process allocation logic contains both COOP and CORP-P, and
  3. Blocking memory measurement API on both COOP and CORP-P.

Unifying COOP and CORP-P completely will work. To me, pros is

  1. We can share the common infrastructure (e.g., reporting),
  2. Figuring out a header value is probably easier than figuring out a header name

and cons is

  1. The policy has a big side-effect (affecting all subresource load), and
  2. COOP will have another rule for same-origin navigation.

Do you agree with that?

@mikewest

This comment has been minimized.

Copy link
Member

commented Jun 18, 2019

I put together a pretty rough pass1 at what I think this thread converged on at https://mikewest.github.io/corpp/, though I see now that I missed @arturjanc's reporting discussion. Would reporting for resources blocked via CORP be useful? Is there a reasonable way to set it up?

@yutakahirano: I threw something on your calendar for tomorrow to chat a bit more about the shape of the mechanism. I'm not convinced that it's a good idea to merge COOP and COEP (née CORPP), as it feels better to me to have small primitives that we then compose to produce behavior we're interested in. On the other hand, there's value in giving developers a clear Gimmie: SharedArrayBuffers header that they could set instead. Hrm. Let's chat!


1: FWIW, I don't intend the stand-alone document to be normative. It's just there to summarize the eventual PRs we'll iterate on in a way that's hopefully more comprehensible than it would otherwise be. I'm still trying to figure out what this kind of document should look like... Bear with me.

@annevk

This comment has been minimized.

Copy link
Member Author

commented Jun 18, 2019

I'm happy calling it COEP. It is indeed a downside one will always have to set COOP as well when COEP is a prerequisite for something. From that perspective it seems attractive to make COEP a COOP-keyword, however:

  1. This will make COOP quite convoluted (and would require some redesign)
  2. This would not necessarily enable more gradual opt-in, whereby you set COEP all the time, even when you're framed. (This would not enable functionality for the site, but would ensure all its resources are consistently fetched correctly.)

I can create a "topic: cross-origin-embedding-policy" label so we can discuss some of the issues with the document separately. Would that work?

@mikewest

This comment has been minimized.

Copy link
Member

commented Jun 18, 2019

  1. This will make COOP quite convoluted (and would require some redesign)
  2. This would not necessarily enable more gradual opt-in, whereby you set COEP all the time, even when you're framed. (This would not enable functionality for the site, but would ensure all its resources are consistently fetched correctly.)

I agree with both of these points.

I can create a "topic: cross-origin-embedding-policy" label so we can discuss some of the issues with the document separately. Would that work?

That's fine by me. That said, the document is rough enough that it might be possible to give broad directional feedback here so I can take a second pass before splitting it into separate issues and then PRs. If the document's close enough to make specific feedback reasonable from your perspective, I'm totally happy to accept it in smaller issues under the label you proposed.

@mikewest

This comment has been minimized.

Copy link
Member

commented Jun 19, 2019

Added more questions to the doc after talking through it with @arturjanc and @yutakahirano, but I think we generally think it's consistent with what we've been discussing here. I'll throw it at a few more people for feedback.

@othermaciej

This comment has been minimized.

Copy link
Collaborator

commented Jun 19, 2019

While CORPP was a silly name, the relation between Cross-Origin-Resource-Policy and Cross-Origin-Embedding-Policy is not clear from the names.

Reading Mike's document without first paging in all these discussions:

  • I briefly thought Cross-Origin-Embedding-Policy was an alternate name, leftover name, or rename for Cross-Origin-Resource-Policy. I only later realized it was meant to be a rename for what was once Cross-Origin-Resource-Policy-Policy.
  • I couldn't immediately guess which is for the page doing the embedder (or not) and which is for the page being embedded (or not), I couldn't tell. Simple change that would solve one side: Cross-Origin-Embedder-Policy. Or for more parallelism Cross-Origin-Resource-Usage(-Policy).

Sorry for the extra coat on the bike shed!

I have skimmed the document but don't have any more substantive feedback yet. It has a good level of detail.

@annevk

This comment has been minimized.

Copy link
Member Author

commented Jun 19, 2019

I'm okay with both of those suggestions, with a slight preference for CO-Embedder-P over CORUP. (Though to be fair, there's probably a lot of names Mozilla could be comfortable with at this point.)

Some initial feedback on the document:

  • Issue 1 seems placed incorrectly. My feedback was about a valid embedder policy and an invalid resource policy. To me it seemed that allowing the resource to be more than same-origin in that case would enable side channel attacks in user agents that don't yet support the new syntax.
  • It should use https://fetch.spec.whatwg.org/#concept-header-list-get to get the header value. (I'm happy to add "get and decode" if you'd prefer operating on strings.) You'll also need to account for there not being a value.
  • "If header matches the sh-token grammar" I don't think this is needed or something we expect implementers to do. The idea should be to get the value, then parse it.
  • I don't think we need "creator embedding policy" as persisted state since we directly set it on the document when creating the browsing context and there's nothing else that needs it as far as I can tell.
  • For dedicated workers we need to enforce that the flag is set (or force inherit it) as they end up in the same agent cluster (and the same browsing context group which is the theoretical process boundary (and practical in some deployments) for the purposes of COOP and COEP).
  • "We might not need to inhert the COEP state into auxiliary frames" I think we have to if we want to allow SAB in combination with unsafe-allow-outgoing.
  • As for inheritance vs requiring the header (issue 4), note #4175 (comment). I'm not sure I entirely agree with that still as if they don't set COOP they won't get SAB when loaded in a top-level. And if they don't set COEP they get different fetching behavior when loaded in a top-level which is also confusing. So slight preference for requiring COEP.
  • As for shared/service workers: COEP there is useful to enable SAB in those contexts. If an implementation wants to put a shared/service worker in the same process as a same origin document with COEP/COOP, the shared/service worker will need COEP, as otherwise the document could use a shared/service worker for attacks. From a specification perspective a shared/service worker creates its own agent cluster and can be process-separated from the rest and Mozilla has been assuming thus far that this is a possibility for all implementations.
@mikewest

This comment has been minimized.

Copy link
Member

commented Jun 20, 2019

s/Cross-Origin-Embedding-Policy/Cross-Origin-Embedder-Policy/

Done in mikewest/corpp@a7433c5 (but I think we'll probably revisit this, as both seem ambiguous! :) ).

Issue 1 seems placed incorrectly.

Then I think I misunderstood your feedback. Let me try again: CORP currently fails open in the face of an unknown value. You're suggesting that if this flag is set, we should instead fail closed. I think I can accept that conceptually, but would suggest that there are extensions to CORP (whatwg/fetch#760 in particular) that I'd really like to get in before we lock it down. If we don't, I think it's going to be much more difficult to ship those extensions, and I think that would make me sad.

It should use https://fetch.spec.whatwg.org/#concept-header-list-get to get the header value.
...
"If header matches the sh-token grammar" I don't think this is needed or something we expect implementers to do.

It would be nice to clarify the integration between Fetch's concept of headers, and the algorithms in https://tools.ietf.org/html/draft-ietf-httpbis-header-structure. I'm attempting to use the parsing algorithm defined in Section 4.2, and I'm not really sure where @mnot, et al envision this processing happening and whether the requirements actually mesh. For example, the parsing algorithm requires ASCII, while I'm pretty sure Fetch doesn't. In any event, I think you're right, Anne, that I should grab the header from the header list and parse it as text: mikewest/corpp@ec62f6d

I don't think we need "creator embedding policy" as persisted state

Got it: mikewest/corpp@4ad7dab (I think we might be able to drop "creator referrer policy" as well?).

For dedicated workers we need to enforce that the flag is set (or force inherit it)

I think this is what the document currently says (in the first block of step 3 of https://mikewest.github.io/corpp/#initialize-embedding-policy-for-global).

"We might not need to inhert the COEP state into auxiliary frames" I think we have to if we want to allow SAB in combination with unsafe-allow-outgoing.

Wouldn't unsafe-allow-outgoing create a new browsing context group for the auxiliary window?

As for inheritance vs requiring the header (issue 4) ... slight preference for requiring COEP.

I agree, and I think this is where @arturjanc and @yutakahirano came down as well. It seems marginally safer for the document to explicitly opt-into the whole mechanism. That also seems marginally more complicated for developers to adopt. We also suggested that it's easier to take restrictions away in the future than to add them ex post facto.

I think this will require changes to the navigation algorithm, probably putting another check into step 1 of https://html.spec.whatwg.org/#process-a-navigate-response (alongside CSP's frame check and the as-yet-undefined X-Frame-Options).

Shared/ServiceWorkers

I think you're correct regarding the process model for shared and service workers.

I worry a bit about a service worker that does not assert COEP fetching resources that do not assert CORP, and laundering them into a document that does require CORP. In the current algorithm, the CORP check is called in "HTTP-network-or-cache fetch", which I think is skipped when responses come from a service worker.

Would moving that check to somewhere more like step 11 of https://fetch.spec.whatwg.org/#main-fetch be reasonable? I think that would address this concern by applying the checks to all responses, regardless of origin.

@annevk

This comment has been minimized.

Copy link
Member Author

commented Jun 20, 2019

  • I suspect we might have to reject if the header value contains non-ASCII? After you do the decode you could do "is value an ASCII string" and treat it equivalently to a parse failure I suppose. It would be kind of nice if the caller did not have to do that though if all algorithms essentially require it. (File an issue at https://github.com/httpwg/http-extensions/issues/new?)
  • It does seem like creator referrer policy is unneeded, at least per HTML and the Referrer Policy standards: filed #4721.
  • If you do not specify unsafe-allow-outgoing, then non-matching popups will end up in their own browsing context group (and become a new top-level browsing that is not an auxiliary browsing context). If you do specify it they are allowed to not match and become auxiliary browsing contexts in the current browsing context group. https://gist.github.com/annevk/6f2dd8c79c77123f39797f6bdac43f3e has details. (Perhaps I should move that to a repository as well, as we are tweaking the model a bit. Or perhaps we should define it together with COEP given the overlap in a couple of cases.)
  • Yes, we'd have to move the CORP check to reject opaque responses without the header from a service worker. I don't think step 11 is appropriate because then redirects are not checked. We'll also need to change the "CORS flag" thing to instead check it being an opaque response.
@mikewest

This comment has been minimized.

Copy link
Member

commented Jun 21, 2019

I suspect we might have to reject if the header value contains non-ASCII?

Added an issue to the document, and poked at httpwg/http-extensions#662 for clarification.

If you do specify it they are allowed to not match and become auxiliary browsing contexts in the current browsing context group.

Hrm. Does that match your understanding, @arturjanc? I find it a little surprising, but I'm also a bit out of the loop on COOP. :(

Or perhaps we should define it together with COEP given the overlap in a couple of cases.

I think defining COOP on its own is valuable, as it seems self-contained as a primitive that can be implemented and understood on its own, and complicated enough to benefit from a little bit of additional explanation around its purpose and approach.

That said, I think it would be very valuable to have a single, developer-facing document somewhere that outlined what impacts COOP and COEP have on the process model and on the availability of various APIs.

I don't think step 11 is appropriate because then redirects are not checked.

Would a new step inbetween 4 and 5 of https://fetch.spec.whatwg.org/#http-fetch be more appropriate? If not, do you have a different suggestion? :)

@arturjanc

This comment has been minimized.

Copy link

commented Jun 21, 2019

"We might not need to inhert the COEP state into auxiliary frames" I think we have to if we want to allow SAB in combination with unsafe-allow-outgoing.

Hrm. Does that match your understanding, @arturjanc? I find it a little surprising, but I'm also a bit out of the loop on COOP. :(

I assumed that we would not allow SAB unless a page has COOP without unsafe-allow-outgoing; otherwise, an attacker could open non-cooperating documents in the same browsing context group and leak their contents. Ideally, SAB would only be available if you have COEP + COOP: same-origin.

The other values modes of COOP (same-site and unsafe-allow-outgoing) are still useful for sites that want to protect themselves from cross-origin attackers, but the restrictive mode that gives you SAB should probably require a stricter COOP.

@annevk

This comment has been minimized.

Copy link
Member Author

commented Jun 23, 2019

How could it open non-cooperating documents if COEP is set as well?

@annevk annevk changed the title Opting into a CORS-only mode (Cross-Origin) Making postMessage() work for SharedArrayBuffer (Cross-Origin-Embedder-Policy) Jun 23, 2019

@arturjanc

This comment has been minimized.

Copy link

commented Jun 23, 2019

It doesn't seem necessary for COEP to inherit into auxiliary documents, see Issue 4 in §3.1.1 in Mike's doc. If we required it then documents with SAB couldn't open popups to non-cooperating cross-origin documents, even though this would be safe because COOP would put them in a new browsing context group (it also seems inconsistent because presumably we'd allow regular navigations from the main COOP+COEP document to another document without the headers, relying on COOP to force a process swap).

IMHO it's also cleaner for COEP to only affect resource loads within the document and its iframes (primarily for the sake of browsers without OOPIFs) and leave it to COOP to put top-level documents in different browsing context groups; this should still give us the security properties we're looking for.

@annevk

This comment has been minimized.

Copy link
Member Author

commented Jun 25, 2019

I think I'm okay with the model where COOP is effectively in charge as to whether or not a new browsing context group is to be created, while having to check COEP occassionally when doing so in order to make the right decision. This would indeed not work if unsafe-allow-outgoing would not disable SharedArrayBuffer as then COEP would also have to be in charge (as we'd have top-level documents without COOP enforcement).

@mikewest

This comment has been minimized.

Copy link
Member

commented Jun 25, 2019

Ok. I'll update the COEP doc, and take a stab at a COOP doc. @arturjanc said he was willing to write a developer-facing threat model / process model doc. Maybe these will all end up being the same doc? Who knows.

I think we're pretty close to turning these into PRs and tests. :)

@rniwa

This comment has been minimized.

Copy link
Collaborator

commented Jun 25, 2019

This has been a very long discussion and it's getting hard to follow what the latest proposal & consensus are. Can someone post a summary of the current COEP / COOP proposal?

@arturjanc

This comment has been minimized.

Copy link

commented Jun 25, 2019

I started putting together a developer-facing COEP + COOP => SAB explainer of sorts, and should have something by tomorrow (it won't be perfect but it will hopefully be a starting point for something usable).

@annevk

This comment has been minimized.

Copy link
Member Author

commented Jul 2, 2019

I have updated https://gist.github.com/annevk/6f2dd8c79c77123f39797f6bdac43f3e (Cross-Origin-Opener-Policy description) to account for unsafe-inherit (see #4581) and Cross-Origin-Embedder-Policy. In particular, how and when Cross-Origin-Embedder-Policy influences the "match". I hope this can help Mike's document and it might help Ryosuke though I think Artur will also post his high-level document soon.

@arturjanc

This comment has been minimized.

Copy link

commented Jul 3, 2019

Apologies for the delay... Thanks to @mikewest's COEP spec and with a lot of help from @csreis and @annevk I jotted down a summary of the current proposal for COOP+COEP, along with some developer guidance for deploying the headers in this doc. This is by no means final, but should hopefully capture the main points from the various assorted discussions we've had -- please take a look and comment in the doc.

@Malvoz

This comment has been minimized.

Copy link
Contributor

commented Jul 3, 2019

In the document:

Cross-origin resources can opt in via CORP (with a Cross-Origin-Resource-Policy header with a value which includes the requester, e.g., same-site, or cross-site for public resources)

But for CORP only same-site and same-origin is defined. So rather than cross-site it'd be the absence of a CORP header?

@annevk

This comment has been minimized.

Copy link
Member Author

commented Jul 3, 2019

No, that's a new value. Absence of the header when COEP is in effect would result in a network error.

@arturjanc

This comment has been minimized.

Copy link

commented Jul 3, 2019

A small caveat to the above is that the CORP requirement would apply only to non-same-origin resources. Loading same-origin resources would be allowed when COEP is in effect under (3) in §3.2.1 (same-origin iframes would still need to set COEP, though.)

CORP cross-site is defined in https://mikewest.github.io/corpp/#integration-fetch

@annevk

This comment has been minimized.

Copy link
Member Author

commented Jul 8, 2019

While thinking about tests (if you want to help, please see web-platform-tests/wpt#17606 for material to review and contribute to):

  1. I think we should make workers specify COEP directly rather than inherit it and have enforcement be more similar to frames.
  2. I wonder if we should allow style sheets to specify a policy as well, similar to https://w3c.github.io/webappsec-referrer-policy/#integration-with-css. The main advantage would be that if you share your style sheets with others, they have a consistent fetching policy throughout. (This does not really work for scripts (except perhaps for imports).)
@clelland

This comment has been minimized.

Copy link
Contributor

commented Jul 29, 2019

Somewhere along the way here I lost track of where credentialless subresources fit in the model -- has that been dropped entirely, or is there some way to achieve it with COEP/CORP?

I'd love to be able to use this to declare that certain subresources are public, having been fetched over the public internet (per CORS-1918), without any cookies/credentials attached.

I don't see it in the current proposal, but I could imagine something like Cross-Origin-Embedder-Policy: no-credentials being used to force that mode.

@annevk

This comment has been minimized.

Copy link
Member Author

commented Aug 9, 2019

That's not part of the MVP and given the complexity of the "public internet" bit I don't think it should be. I'd support experimenting with it and iterating on it in parallel though. Would you mind opening a new issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.