Websites should have an explicit way to restrict any kind of cross-origin load to protect themselves against Spectre attacks. Content such as images, video, and audio may be sensitive and websites may be protected solely by virtue of their network position (inside a firewall), relying on the same-origin policy to protect against exfiltration.
There's a previous proposal from 2012 called the From-Origin header that we'd like to resurrect. With it, a server can send a From-Origin : same header on responses it wants to protect from Spectre attacks. Here's a snippet from the currently inactive proposal:
The From-Origin header can be used to restrict embedding of a resource to only certain origins. When used it must match the following ABNF:
From-Origin = "From-Origin" ":" #(serialized-origin | "same")
Cross-Origin Read Blocking (CORB) automatically protects against Spectre attacks that load cross-origin, cross-type HTML, XML, and JSON resources, and is based on the browser’s ability to distinguish resource types. We think CORB is a good idea. From-Origin would offer servers an opt-in protection beyond CORB.
In addition to the original proposal, we might want to offer servers a way to say cross-origin requests are OK within the same eTLD+1, e.g. the server may want to say that cross-origin subresources from cdn.example.com may be loaded from *.example.com without listing all those origins.
Ping @whatwg/security.
Previous discussion https://github.com/whatwg/fetch/issues/365
@mystor @ehsan
This might be OK to add as a stopgap, as long as we're clear that it doesn't actually solve the problem in general. We generally want a safe-by-default solution, not one that requires every single server to opt in...
Just to be clear - this is scoped to the response it occurs within, correct?
Yes. It is not stateful. The security benefit is that the browser can cancel the load and not bring the payload or meta data into the process where JavaScript is executed.
@johnwilander: Thanks, this does seem like a good fit for CORB, giving web sites a way to opt in to protection on arbitrary resources (not just HTML, XML, and JSON, though it would be a good failsafe for those as well).
@bzbarsky: I agree that both CORB and From-Origin only protect a subset of resources-- the largest we could come up with while preserving compatibility, plus anything sites choose to label with From-Origin. I agree with you that a secure-by-default solution would be preferable, but I'm not yet aware of one that can be easily deployed, at least in the short term. (For example, the idea of using credential-less requests for all subresource requests doesn't seem web compatible.) Happy to discuss options there.
I do think it's worth pursuing CORB and From-Origin at least as a stop-gap in the short term, since there's a fairly pressing need to get protection out there for as many resources as we can.
Let's discuss the subdomain aspect of this.
We'd like servers to be able to express that all pages from the same eTLD+1 are allowed to load the resource. The 2012 proposal as it stands requires the server to list all allowed domains which is error prone and uses up bytes on the wire.
Instead of having a resource on example.com send a response header like this:
From-Origin: cdn1.example.com, cd2.example.com, www.example.com, secure.example.com, example.com, many.sub.domains.of.example.com
... it could send something like this:
From-Origin: SamePrimary
... which would match example.com and any chain of subdomains of example.com. WebKit often refers to eTLD+1 as the partition.
There are at least two pieces of prior art here, none of which seem to fit our needs:
To further complicate things, eTLD+1 has many names:
Some naming ideas:
From-Origin : SamePartitionFrom-Origin : SamePrimaryFrom-Origin : SamePrimaryDomainFrom-Origin : SameTPODFrom-Origin : SameETLD+1From-Origin : SameETLDPlus1From-Origin : SameETLDPlusOneFrom-Origin : SamePublicSuffixPlus1From-Origin : SamePublicSuffixPlusOneChrome and Firefox efforts seem to call that boundary "site", which is also reasonably understandable. So to add to your bikeshed, I'd argue for From-Origin: same-site.
The other thing we need to make concrete is for which responses this applies. Pretty much everything but top-level navigations? (For bonus points, would it apply to OSCP? See also #530.)
Something in this space seems like a good idea, so I'm supportive of the general direction.
I wonder, though, whether it would be simpler to build on existing primitives rather than add a new header. For example: what if we started sending an Origin header with every request? Presumably, servers that would opt-into sending a From-Origin header would also be capable of blocking requests with unexpected Origin headers before passing the requests on to applications that might be damaged? (FWIW, I've also been toying around with the idea of sending a lower-granularity Origin header as part of some future authentication primitive, which would boil down to an enum of cross-site/same-site/same-origin).
From-Origin is potentially simpler to deploy for some endpoints that expect same-site usage, but always sending an indication of a request's provenance gives servers a lot of flexibility in how they deal with incoming requests. Since they're already dealing with that header for access control in general, relying upon it more broadly might be less overhead than creating a new primitive for the same purpose.
To further complicate things, eTLD+1 has many names:
On this point in particular, I'd suggest that we'd be well-served to follow the PSL's "registered domain"/"registrable domain" terminology, or to follow the "site" terminology that SameSite cookies defines, that Chrome's "Site Isolation" uses, etc. I don't believe the other terms listed above are as commonly used, but I'm happy to just agree on some spelling of the concept and putting it into a more easily-referencable document.
Pretty sure Adam Barth tried Origin on each request to combat XSRF and it's simply not web compatible. That's why we ended up with the rules for it we have today.
Pretty sure Adam Barth tried
Originon each request to combat XSRF and it's simply not web compatible. That's why we ended up with the rules for it we have today.
If the objection is purely practical, perhaps @abarth could help us recall the challenges he ran into? I'd suggest that CORS is baked-into enough of the web at this point that it might be worth trying again (especially since I think there's at least tentative agreement from Firefox folks to expand Origin's coverage to include some subset of non-GET/HEAD requests).
I don't remember exactly, but I think the idea was to avoid request bloat. Adding bytes to every request is (or at least pre-HTTP/2.0 was) expensive, whereas scoping the extra bytes to POST made them negligible.
We've explored the idea of expanding Origin header in the request as well but the challenge we face there is deployability. It's a lot easier for websites to deploy From-Origin header on all resources than checking Origin header on every resource request while keeping it compatible with old browsers that don't send this request, etc...
We've explored the idea of expanding
Originheader in the request as well but the challenge we face there is deployability. It's a lot easier for websites to deployFrom-Originheader on all resources than checkingOriginheader on every resource request while keeping it compatible with old browsers that don't send this request, etc...
I think I agree that From-Origin is easier to deploy for servers, as it doesn't require much in the way of server-side logic. If we expand the scope of the Origin header, servers would need to read it, process it, and do something useful with it, which certainly takes some effort. I'd suggest that expanding the scope of Origin has the additional benefit of giving servers the tools to more broadly mitigate CSRF attacks, but I'm willing to believe that fewer folks would be interested in doing the extra work. I think it's worth experimenting with that approach, but there's no reason we couldn't do both.
I have a few detail questions:
@annevk suggested that this should apply to everything except top-level navigations. That misses auxiliary browsing contexts created via window.open, which I imagine are same-process in some browsers. Would we want to address that vector as well?
Does From-Origin: SameSite (or however we end up spelling it), walk up the ancestor tree, or do we base the check purely on the initiating origin? We've recently fixed X-Frame-Options: SAMEORIGIN to align with frame-ancestors by checking the entire tree, and I'd suggest that that's the right behavior here as well.
We apparently talked about this in https://github.com/w3c/webappsec-csp/issues/17 as well. I'm less enthusiastic about adding new directives to CSP than I was in 2015, but it's worth evaluating whether we should consider this an analog to frame-ancestors by adding a new CSP directive, or if we should add a new header entirely.
Would we apply this to redirect responses, or just final responses? I vaguely recall differences in X-Frame-Options behavior on this point between browsers, so it's probably worth hammering out (FWIW, I'd suggest that we should apply the check to redirect responses, returning an error rather than following the redirect, as appropriate).
I'm not certain it makes sense to prevent window.open on the basis that some browsers don't support it today.
We should probably match frame-ancestors.
I'd defer this to @johnwilander
Yes, we absolutely have to apply this to all redirect responses.
Thanks, @rniwa!
I'm not certain it makes sense to prevent window.open on the basis that some browsers don't support it today.
If the purpose is to prevent an origin's data from entering a process, I'd suggest that we need to be as thorough as possible in reducing an attacker's opportunity. Because window.open gives the opening context a handle to the newly opened window, it gains script access to that window. Chrome's implementation only recently allowed us to push those newly opened windows into separate processes. I'd be thrilled to hear that other vendors have done the same. shrug
Note that the window.open() vector can be emulated via <a target=...>.
WebKit is working to isolate window.open and other contexts with opener in a separate process as we speak.
Blocking them in window.open and <a target="_blank"> can be a good mitigation for a short term though. I guess the question is whether we should make that behavior optional or mandatory. Or if we should make From-Origin imply that, or add yet another header/CSP option to enforce it.
Another option for window.open(~) and <a target="_blank"> is to disable nullify opener when this header / CSP option is set so that browser engines can easily put it into a different process.
We've discussed this further and have some thoughts.
Let's assume a main goal of From-Origin is to provide servers with a way to prevent their resources from being pulled into a process space where they can targeted by a Spectre attack.
Only checking the origin of the request does not suffice in the nested frame case. This means just adding Origin headers to requests is not enough, leaving aside ease of deployment.
Checking the ancestor list upward is not enough. Checking it up and down is not enough either. What is needed here is a guarantee that, at the time of the request, there is no cross-origin or non-same-site frames in the web content process. This includes sibling frames at any level.
Even with such a guarantee _at the time of the request_, cross-origin or non-same-site frames may be loaded into the process at a later stage and a Spectre attack could be possible. The only way we see this fully working is checking that no cross-origin or non-same-site frames are in the process at the time of the request, and blocking any subsequent cross-origin or non-same-site frame loads into the process.
What do you think?
(We might start with the simple version of just checking against the origin of the request.)
John, I'm not sure I follow the frame-focused reasoning in your proposal; IIUC under this logic evil.com could not have any frames but still load victim.com/secret.txt as an <img> or another subresource type, which would then allow it to exfiltrate its contents. Or am I misunderstanding the approach?
Wouldn't the real solution for Spectre-like exfiltration be to have something like https://www.chromium.org/developers/design-documents/oop-iframes?
@arturjanc: The idea here is that img, script, etc... won't be able to load these resources if From-Orign doesn't allow it. In other words, From-Origin basically removes non-CORS cross-origin resource loading.
On Fri, Apr 6, 2018 at 7:00 PM, arturjanc notifications@github.com wrote:
John, I'm not sure I follow the frame-focused reasoning in your proposal;
IIUC under this logic evil.com could not have any frames but still load
victim.com/secret.txt as anor another subresource type, which
would then allow it to exfiltrate its contents. Or am I misunderstanding
the approach?I assume that victim.com/secret.txt would be served with a response
header like "From-Origin: https://victim.com" and therefore the browser
would prevent this resource from being loaded into the renderer process
hosting evil.com (i.e. the browser would stop the load unless it can
guarantee that the target renderer only hosts data from the
https://victim.com origin).
Wouldn't the real solution from Spectre-like exfiltration be to have
something like https://www.chromium.org/developers/design-documents/
oop-iframes?Different browsers can approach the "can guarantee that the target renderer
only hosts data from the https://victim.com origin" problem in different
ways. Current plan of action for Chromium is to use out-of-process
iframes, but even without oop-iframes a browser can track which
origins/sites are hosted in a renderer process and block resource loads /
frame embedding as needed (possibly in a way that breaks legacy users of
resource marked this way - this is why mechanisms like "From-Origin: ..."
or "X-Frame-Options: SAMEORIGIN" are needed as an opt-in mechanism).
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/whatwg/fetch/issues/687#issuecomment-379424368, or mute
the thread
https://github.com/notifications/unsubscribe-auth/ALoIqKSQiKNZll_5WY9NCVpigi-Kr-Qzks5tmB29gaJpZM4S--lq
.
@johnwilander does that mean you're not doing out-of-process <iframe>? In any event, what you're saying there sounds like a totally different thing from From-Origin. If you want it affect more than just the response it's on it'd be good to have a new name for that proposal, to keep them somewhat separate.
Maybe all browsers will ship process-per-origin, on by default, in a month, but I doubt it. :) Maybe all browsers will be fine spinning up ~70 processes to load a news page, but I doubt it.
If I’m right, we need an interim solution for sensitive resources. Hence, CORB and this From-Origin thread. Once all browsers do process-per-origin by default, this header will not be needed for Spectre protection but may still me useful to ensure that no third parties are involved in this resource load.
This header is useful even with process-per-origin/site, since the whole point is preventing yourself from ending up as a no-cors resource in an attacker origin. Process-per-origin/site wouldn't help with that. That's what I thought we were going for. If we want to go beyond that, we should probably discuss requirements again, since it's not entirely clear to me what this is going to help with then and how.
I think john's comment is related to:
Does From-Origin: SameSite (or however we end up spelling it), walk up the ancestor tree, or do we base the check purely on the initiating origin? We've recently fixed X-Frame-Options: SAMEORIGIN to align with frame-ancestors by checking the entire tree, and I'd suggest that that's the right behavior here as well.
My understanding is that the simple check on the initiating origin is probably good enough but I may be overlooking things here.
AIUI, there might be some attacks whenever there is any cross-origin iframe loaded in the same process, at the time of the load or after the load.
Going through the ancestor tree or even through the list of frames in a process will not give a full protection.
And I am not sure this will be useful at all in case of out-of-process iframes.
And I am not sure this will be useful at all in case of out-of-process iframes.
Not useful for specter, question is whether it is useful for other kinds of attacks.
I've been following this thread while on vacation and didn't have time to comment until now, but this is an important problem that I also feel strongly about solving (thank you @johnwilander for starting this discussion!). Since there are a lot of ideas here, I wanted to summarize the discussion as I understand it, and compare the benefits of the proposals that came up.
As background, in the past we've thought a fair amount about protecting applications from cross-origin information leaks -- allowing developers to prevent their applications' endpoints from being loaded as subresources of an attacker-controlled document goes far beyond protecting the exploitation of Spectre-like bugs, and can address a large number of cross-origin attacks we've seen over the past decade.
Specifically, having the browser refuse to load protected resources in the context of the attacker's origin/process, could help solve the following classes of issues: cross-site script inclusion (XSSI), cross-site search, CSS-based exfiltration, as well as Spectre. Telling the server about the requester's origin as Mike suggested above would also give developers the chance to prevent most kinds of attacks based on cross-origin timings and CSRF -- the server could be configured to only accept subresource requests coming from trusted origins.
For completeness, addressing these kinds of issues was part of the motivation for EPR and Isolate-Me, as well as for same-site cookies. But these proposals are fairly heavy-weight to implement and adopt, and there is value in having a simpler mechanism to tackle the classes of issues mentioned above.
IIUC the discussion here focused on two main alternatives:
From-Origin response header as outlined in Anne's original proposal which would prevent the browser from exposing the contents of the response to non-safelisted origins.The first option is somewhat simpler and makes the protection more explicit; in some cases, developers might be able to set From-Origin: same on all responses and that would be sufficient to protect against Spectre and some cross-origin leaks. The second option requires more work on part of the server (adding logic to decide whether to respond to a request based on its sender), but it's more flexible and more powerful because it can also protect against CSRF and timing attacks, though with some caveats.
As a data point from someone who works with a large number of non-trivial applications, I feel that it might be somewhat easier to adopt this if we go with option 2, possibly with a new request header, e.g. Sec-Requesting-Origin -- we might not be able to reuse Origin because of backwards compatibility issues, though I'm not 100% sure about this. On the server side, the logic would boil down to checking if the header is present in the request, and if so, rejecting requests if the requesting origin isn't trusted (if there is no header, or the origin is trusted, return the response as usual).
If browsers were to consistently set this header, developers could start by collecting data about origins which are already requesting authenticated resources from their application by collecting header values, and then turn on enforcement by returning empty responses if the requesting origin isn't trusted. This could also work even if there is a Referrer Policy of no-referrer if we make the user-agent send a special identifier to include some coarse-grained information about the source (e.g. same-origin, same-site or cross-site as Mike suggested above). If we're worried about the number of bytes on the wire this would add to requests, it could be require an opt-in via an Origin Manifest or a header-based mechanisms similar to HSTS. Finally, we could also consider having a special way to annotate navigational requests to protect against the exploitation of CSRF via top-level navigations.
I think this would be powerful enough to allow application developers to protect from Spectre, especially if combined with default protections via CORB, and would simultaneously allow developers to protect against other cross-origin leaks. From-Origin as originally described in Anne's doc seems workable as well, but is a little more constrained -- perhaps there really is value in doing both things?
Regarding tying From-Origin protections to the absence of cross-origin/site frames: this seems like it would significantly limit the utility of the mechanism, leading to most applications not being able to deploy it.
Note that developers already have a way to ensure that their document is not iframed by an untrusted origin and does not contain iframes from untrusted origins; they could set an origin-wide CSP of frame-ancestors 'self'; frame-src 'self'. It's perfectly fine to explain to them why they might want to set such a policy on their sites, but there are many scenarios where the developer might willingly iframe a trusted cross-origin/site document on a page which uses a resource that should be protected from Spectre-like attacks. I hope we wouldn't prevent developers from securing their resources in this scenario.
I think I'd be somewhat supportive of something like Sec-Site with same-origin/same/cross as values. Generalizing Origin would indeed undo a lot of referrer protection that I'm not super comfortable with. Making it opt-in seems nice, but that also means we cannot realistically deploy it soon, since I'd assume we'd want to wait for origin manifests to become a thing.
The cost of adding From-Origin on the other hand seems fairly low and something we could implement pretty quickly allowing particularly sensitive resources to deploy protection soonish.
Thanks, Anne -- in this case, let's leave the Sec-Site question for a separate thread and focus on From-Origin here. I like the idea and think we should do it, but there are two caveats that are worth pointing out:
From-Origin may be tricky in a fair number of applications because developers don't have visibility into the requesters of their resources. E.g. if they start serving From-Origin: "same" on resources that are legitimately loaded by a non-same-origin document, these loads will break in a way that's not easy to identify or predict in advance (short of first doing a study which gathers Referer values -- which isn't foolproof because of Referrer Policy and the header being stripped in many cases).Both of these are fine if we see the header as a narrowly focused Spectre mitigation for responses not covered by CORB, such as images, but I think there is still room to do more and address cross-origin leaks (and Spectre) in a more general way.
Somewhat separately, I'd also suggest making the source list syntax compatible with CSP (e.g. 'self' instead of "same", etc.)
Using the same syntax as CSP sounds good.
While there are many considerations to take with respect to Spectre, why don't we start from the simplest form of the proposal?
Starting point: From-Origin response header, if set, prevents the resource with this header from being loaded in the origin not specified by the header.
Now let's define the semantics before syntax.
First off, can we all agree that this response header should apply to all resource types? HTML, CSS, images, etc...?
Can we also agree that this should affect all types of resource loads? img element, script element, sync & async XHR, fetch, etc...
Then we need to decide what it means to be loaded in a document of an origin. There are a few options here:
Here's my take from Spectre protection standpoint.
In browsers that do support process-per-origin or process-per-frame, (1) and (2) work best. (3) requires websites to actively prevent their origin's documents from being loaded in other origin's iframes.
In browsers that don't support PPO/PPF, all these options are okay if we're aiming for the opt-in from websites depending on what changes websites can make to protect themselves. For (2) and (3), websites can prevent any of its pages to be loaded inside an untrusted document's iframe with CSP or X-Frame-Options.
(4) works best because if there was any document of an untrusted origin in the same process as the opted-in frame, all bets are off against a Spectre attack. However, (4) is only half the solution. We also need to prevent new documents of an untrusted origin from being loaded e.g. by navigating existing iframes or inserting new frames.
I don't think we want to have that kind of side-effect in the document to which these resources are loaded.
Applying to all resource types/loads sounds reasonable to me.
When it comes to what it means to be loaded from a document of a given origin, the most obvious answer seems to be (2): "check the origin of the document in which the resource is loaded", which is consistent with how other parts of the platform work (e.g. the Referer and Origin headers, window.origin, or event.origin in a postMessage all identify the location of the current document, rather than the entire ancestor chain, or set of the origins of all sibling frames.)
The reason I find (4) fairly strange is two-fold:
1) It doesn't seem necessary to have From-Origin effectively control what frames are allowed to load in a given application because developers already have that lever: Content-Security-Policy: frame-src. An application which doesn't ever need to load cross-origin frames can ensure that it's safe from Spectre if it sets frame-src, frame-ancestors and From-Origin, to 'self' on all of its responses even if From-Origin only looks at the origin of the embedding document and ignores frames.
2) Framing a resource is a choice on part of the developer. If the application loads an iframe, it generally means the developer wants the iframe to be part of her application, or otherwise she would remove it (or possibly prevent it from loading via CSP). IIUC option (4) means that developers would be required to either remove all cross-origin frames or set From-Origin to a union of the origins of frames loaded in their application, or otherwise loading From-Origin-protected resources would break. Whitelisting these external origins in From-Origin would mean that any document in these origins would now be able to execute Spectre-like attacks on the application's resources at any time, rather than just the single explicitly iframed document while the user is interacting with the application.
Basically, I don't see how this would be better than letting developers control framing via existing mechanisms and making From-Origin care only about the origin of the document loading the resource.
Agreed that using the origin of the document is a good step forward.
Note though that it would be different from the fetch origin/origin header value in some cases.
One case is cross origin redirections.
The other case is data/blob iframes/workers where what could be used is the origin as computed for service workers
It doesn't seem necessary to have From-Origin effectively control what frames are allowed to load in a given application because developers already have that lever: Content-Security-Policy: frame-src. An application which doesn't ever need to load cross-origin frames can ensure that it's safe from Spectre if it sets frame-src, frame-ancestors and From-Origin, to 'self' on all of its responses even if From-Origin only looks at the origin of the embedding document and ignores frames.
Agreed, though there's still an assumption that other cross-site pages wouldn't end up in the same process, independent of what that application allowed via CSP and From-Origin. For example, in Chrome without Site Isolation, a cross-site page in an entirely unrelated tab might end up in the same process (e.g., if the user has many tabs open and an existing process gets reused for it). If that page had a Spectre attack, it could access the application's data despite being in an unrelated tab.
This could certainly still be prevented if browsers took process sharing into account with From-Origin (as I think is being proposed). I just didn't see it covered in the recent summaries of what browser behavior From-Origin would require. Presumably top-level navigations to pages with From-Origin headers would have to go into dedicated processes that don't get reused for other sites. Implementing that would require cross-process navigations (as @rniwa mentioned earlier), since a tab could start out on an unrestricted page and then navigate to a page with a From-Origin header. Does that sound correct?
Note that 1, 3, and 4 require special considerations for workers (for 2 we can just use the origin of the worker), which can make it rather complicated as they can cross tabs (though they themselves have to be same-origin with the document they're directly associated with, which helps somewhat).
(As for syntax, I actually think we should follow CORS and not require any quotes. It's Origin: null, not Origin: 'null'. So it follows that it's also From-Origin: same.)
It doesn't seem necessary to have From-Origin effectively control what frames are allowed to load in a given application because developers already have that lever: Content-Security-Policy: frame-src. An application which doesn't ever need to load cross-origin frames can ensure that it's safe from Spectre if it sets frame-src, frame-ancestors and From-Origin, to 'self' on all of its responses even if From-Origin only looks at the origin of the embedding document and ignores frames.
Framing a resource is a choice on part of the developer. If the application loads an iframe, it generally means the developer wants the iframe to be part of her application, or otherwise she would remove it (or possibly prevent it from loading via CSP). IIUC option (4) means that developers would be required to either remove all cross-origin frames or set From-Origin to a union of the origins of frames loaded in their application, or otherwise loading From-Origin-protected resources would break. Whitelisting these external origins in From-Origin would mean that any document in these origins would now be able to execute Spectre-like attacks on the application's resources at any time, rather than just the single explicitly iframed document while the user is interacting with the application.
(4) can provide protection if the browser doesn't have process-per-frame/process-per-origin.
If victim.com is the top frame, then yes, it can control the page's CSP. But if victim.com is an iframe, I don't think there is a way for it to tell the browser that it will only allow a particular resource load if all frames in the current web content process are from a given whitelist.
Say you have a situation like this:
friend.com
|
/ \
/ \
evil.com victim.com (CSP allows ancestor friend.com)
iframe iframe
\
Loads sensitive image
evil.com can now Spectre the sensitive image, right? And if From-Origin only checked the ancestor tree, it would not consider evil.com's sibling iframe.
Maybe we could have a strict mode that takes _all_ frame origins in the process into account? I haven't given it any deeper thoughts but wouldn't such a strict mode allow for pretty good UI redressing protection too? Say payments.com makes a deal with shop.com to provide a checkout iframe. It could then refuse to display its content if shop.com's checkout page is loading unknown cross-origin iframes. And that would be beneficial even under process-per-frame/process-per-origin.
Maybe we could have a strict mode that takes all frame origins in the process into account?
It does seem like that would be necessary (both for frames and workers in the process), though not sufficient, as you noted earlier:
Even with such a guarantee at the time of the request, cross-origin or non-same-site frames may be loaded into the process at a later stage and a Spectre attack could be possible. The only way we see this fully working is checking that no cross-origin or non-same-site frames are in the process at the time of the request, and blocking any subsequent cross-origin or non-same-site frame loads into the process.
It does seem like you'd need some notion of marking the process as dedicated to the origin/site, so that future frames and workers from other sites aren't loaded into it.
I haven't given it any deeper thoughts but wouldn't such a strict mode allow for pretty good UI redressing protection too? Say payments.com makes a deal with shop.com to provide a checkout iframe. It could then refuse to display its content if shop.com's checkout page is loading unknown cross-origin iframes. And that would be beneficial even under process-per-frame/process-per-origin.
It might help in the case that cross-site frames are never allowed in the same page. I think it might not help if out-of-process iframes are supported, since those could still do UI redressing attacks in the same page, just from a different process. (That said, out-of-process iframes make it possible to protect a much wider range of pages from Spectre, such as those that do have semi-untrusted cross-site frames.)
For completeness, addressing these kinds of issues was part of the motivation for EPR and Isolate-Me, as well as for same-site cookies. But these proposals are fairly heavy-weight to implement and adopt, and there is value in having a simpler mechanism to tackle the classes of issues mentioned above.
Thanks @arturjanc for mentioning these.
For this discussion, it may actually be useful to read some of the earlier research we did in that space:
"App Isolation: Get the Security of Multiple Browsers with Just One" (CCS 2011)
https://research.google.com/pubs/pub37198.html
That paper had some similarities to the approaches we're considering here: it was an opt-in way for sites to try to protect themselves from attacks, it involved process isolation (as well as state isolation for things like cookies and localStorage), and it was an attempt to get some of the benefits of Site Isolation (e.g., protection from compromised renderer processes) without needing out-of-process iframes.
We wouldn't need everything the paper proposes for Spectre defense (e.g., entry-point restrictions or maybe even the isolation of persistent state), but it might give some useful ways to think about how some web sites could request process isolation, and what the tradeoffs are.
@johnwilander In principle, I don't have a problem with making stricter behavior available as an opt-in.
However, I worry about a model where unrelated cross-origin frames (outside of the ancestor chain of a given document and of the document's own descendants) can directly influence a document's behavior. For example, the situation you described seems to lead to a cross-origin information leak: evil.com can now infer if a frame from victim.com is loaded anywhere in its current process by returning different From-Origin values for its resources and seeing if they render, even if it doesn't have a reference to the victim.com window or its parent. Aside from security concerns, such "action at a distance" may lead to unexpected application failures, and doesn't seem easy to test for or debug.
Putting on my web author hat, the case you're describing is certainly possible, but due to X-Frame-Options lacking fine-grained origin-based controls, the majority of applications seem to default to only allowing same-origin framing; use of frame-ancestors is still relatively sparse. So I'd expect that the number of non-CORB-protected authenticated resources loaded in documents meant to be iframed across origins is relatively small compared to what From-Origin in "mode (2)" would protect from (and, in the case you're describing, those resources would be broken in situations in which they're currently working, so I'm not particularly convinced developers would be eager to opt into this mode.)
For example, the situation you described seems to lead to a cross-origin information leak: evil.com can now infer if a frame from victim.com is loaded anywhere in its current process by returning different From-Origin values for its resources and seeing if they render, even if it doesn't have a reference to the victim.com window or its parent.
Interesting. Yes, that is an issue to consider.
Aside from security concerns, such "action at a distance" may lead to unexpected application failures, and doesn't seem easy to test for or debug.
Agreed. I'm mostly thinking of strict mode as "the big hammer" for cases where a leak is catastrophic and site breakage is tolerable.
This will probably be my first iteration, checking frame ancestors but not all frames in the process:
From-Origin: same for same-origin.
From-Origin: same-site for same eTLD+1.
I think checking all frames is unnecessary. For the same/same-site case, you have to trust that you won't load dangerous third-party iframes anywhere on your site. You can self-enforce this with CSP. For the case where From-Origin specifies other origins, you have to either trust them or assume it's not a Spectre defense and just for purposes like hotlinking prevention.
Another thing to think about: should From-Origin apply to no-credentials requests? Should there be a way to say "it's ok to load my resources cross-origin but not with credentials"?
Should there be a way to say "it's ok to load my resources cross-origin but not with credentials"?
That would be nice, and fit with the best practices promoted for CORS already for public resources: https://fetch.spec.whatwg.org/#basic-safe-cors-protocol-setup. Basically, something that makes img elements etc. play by the same rules as the more modern parts of the platform.
Another thing to think about: should From-Origin apply to no-credentials requests?
If you care about protecting servers where you authenticate with your IP address, then yes.
For the case where From-Origin specifies other origins, you have to either trust them or assume it's not a Spectre defense and just for purposes like hotlinking prevention.
For Spectre, it's not sufficient to just trust the sites that you allow to iframe your pages. Those sites also have to have Spectre defenses of their own, or else an attacker can load them in a shared process via iframes or window.open. Example attack using the names from above:
1) evil.com loads friend.com in same process (e.g., window.open).
2) friend.com loads victim.com in iframe.
3) evil.com accesses victim.com directly using Spectre.
That means that sites would have to be told to only allow embedding on sites they trust which also have effective From-Origin defenses of their own. That might be possible, though it will probably make it harder for some sites in practice.
For example, the situation you described seems to lead to a cross-origin information leak: evil.com can now infer if a frame from victim.com is loaded anywhere in its current process by returning different From-Origin values for its resources and seeing if they render, even if it doesn't have a reference to the victim.com window or its parent.
This could be an issue in general if From-Origin supports a list of origins and checks all frame ancestors. Example:
This is interesting -- I had expected the case mentioned by @TanviHacks might already leak in all browsers via window.location.ancestorOrigins, but it looks like this is true only for Chrome and Safari. From what I see this is due to a conscious decision in Firefox based on @bzbarsky's feedback on https://bugzilla.mozilla.org/show_bug.cgi?id=1085214#c23 and https://github.com/whatwg/html/issues/1918. I agree that this would be concern if a UA wants to prevent a frame from being able to find out the origin of its embedder when the embedder sets Referrer-Policy: no-referrer.
@TanviHacks: If we change step two of your example to "siteB embeds an <iframe src=siteB>...", then I think we've already accepted this risk via X-Frame-Options: ALLOW-FROM ... and Content-Security-Policy: frame-ancestors .... It's not clear to me that there's new capability created by enabling similar functionality for non-frame subresources.
If we decide that we don't want to accept that risk, perhaps we could resolve this by failing closed in the presence of no-referrer. That is, if a page sets no-referrer, then any From-Origin value will fail. That should make it difficult to use these headers to detect a specific site, as all sites, same-origin or not, will fail the check.
That sounds reasonable, except that we should look at "the document's referrer" as per https://github.com/whatwg/html/pull/2480. The difference matters once you start navigating and such.
Initial support landed yesterday: https://trac.webkit.org/changeset/230968/webkit . It'll ship as an off by default experimental feature in Safari Technology Preview. Or you can grab a recent build archive: https://webkit.org/build-archives/
Cool! Here are some further questions and thoughts:
From-Origin: same set, will it fail?same and same-site case-sensitive to be more similar to null and how we compare origins? (I'd suggest yes.)From-Origin headers (either multiple or comma-separated)? We need to be clear on whether same, same-site or same, https://hello.example ends up being ignored or means something.Also, the way WebKit deals with "invalid" values means that if someone deploys From-Origin: https://hello.example today it'll never fail to load in WebKit until they add support for that. Perhaps it's better to be strict from the start here given that origins are best compared byte-for-byte (after splitting on comma and stripping HTTP whitespace)?
Cool! Here are some further questions and thoughts:
If a cross-origin iframe has a same-origin worker and that worker fetches something same-origin with From-Origin: same set, will it fail?
I have yet to add tests for workers but yes, it should fail.
Should we make same and same-site case-sensitive to be more similar to null and how we compare origins? (I'd suggest yes.)
You're saying the header has to say "Same" or "Same-Site," exactly so?
How do we deal with multiple From-Origin headers (either multiple or comma-separated)? We need to be clear on whether same, same-site or same, https://hello.example ends up being ignored or means something.
I'm still not convinced we need whitelisting of individual domains but maybe we do. It just feels like it'll be CSP all over again. Too complex => low adoption. With just Same and Same-Site, it's simple, kind of like XFO and HSTS, which I believe have seen significantly more adoption than CSP.
I'd really like to include that referrer check pointed out above, but it seems a little contingent on being able to ship that for CSP/X-Frame-Options too. Perhaps we can try to be strict here first and if restricting it for CSP/X-Frame-Options fails we loosen this up? (It's also a little different as this always applies, whereas those only affect navigation.)
Did I miss something above? Can you explain what you're referring to? Thanks.
Also, the way WebKit deals with "invalid" values means that if someone deploys From-Origin: https://hello.example today it'll never fail to load in WebKit until they add support for that. Perhaps it's better to be strict from the start here given that origins are best compared byte-for-byte (after splitting on comma and stripping HTTP whitespace)?
We thought about this and discussed it during code review. It comes down to supporting Same and Same-Site for the time being and maybe adding domain whitelisting down the road.
I would not like a header like "From-Origin: Same, compromised.com" to start off enforcing same-origin and then later open up for Spectre attacks from compromised.com two years later when browsers add domain whitelisting.
I want invalid headers to just fail, as in not affect the load, so that what developers deploy today maintains its functionality whatever we add to the header later. I see your point that "From-Origin: compromised.com" would change behavior down the road with my proposal but at least it would not work day one which has a higher likelihood of alerting developers. I'm open to discuss.
@johnwilander I meant same and same-site, lowercase (null is lowercase too: https://fetch.spec.whatwg.org/#origin-header).
I don't have a problem with supporting two values initially, personally.
As for referrer, see https://github.com/whatwg/fetch/issues/687#issuecomment-382128393. The leak is fairly limited if you only support same and same-site, but it still seems worth addressing with an eye on the future I think.
As for error handling, I think either way you open yourself up to problems later. The advantage of failing closed I think is that it's noticed sooner. And if invalid values due spread (as they seem to do for headers), it'll be hard later to enforce a byte-for-byte comparison as many loads will start failing at that point.
I'm still not convinced we need whitelisting of individual domains but maybe we do. It just feels like it'll be CSP all over again. Too complex => low adoption. With just Same and Same-Site, it's simple, kind of like XFO and HSTS, which I believe have seen significantly more adoption than CSP.
Without getting into a full post-mortem of CSP deployment difficulties, I think origin-based source lists are one of CSP's more understandable aspects, so I wouldn't look to them as the reason for low adoption.
The problem with not allowing granular control in From-Origin is that it will be impossible for developers whose resources are loaded cross-site to use the header, even if they fully control the requesting domain. Given that headers such as X-Frame-Options are often set globally for the entire application, this means that developers who have _any_ resources that fall into this category will either see their sites break or will have to manually exempt some resources from From-Origin, which will complicate adoption and reduce the security value of using the mechanism in the first place.
Arguably, the sites that would benefit the most from From-Origin protections are the ones with large userbases, hosting sensitive authenticated content, which often have relatively complex cross-origin loading relationships. It seems to me there'd be a lot of value in making From-Origin work for them, or, if we decide against it, provide another mechanism they can use.
As for error handling, I think either way you open yourself up to problems later. The advantage of failing closed I think is that it's noticed sooner. And if invalid values due spread (as they seem to do for headers), it'll be hard later to enforce a byte-for-byte comparison as many loads will start failing at that point.
As someone who is interested in adopting From-Origin, I think I prefer John's current model of failing open on invalid values because it reduces the potential for breakage. For example, if any browser ships From-Origin without granular origin controls, then developers who need these granular controls will not be able to use them in supporting UAs because it will break functionality for users of the stricter browser. This would mean developers would need to do UA-sniffing, which would significantly increase the complexity of their server-side code (particularly because many frameworks set response headers via a static config.)
The problem with not allowing granular control in From-Origin is that it will be impossible for developers whose resources are loaded cross-site to use the header, even if they fully control the requesting domain. Given that headers such as X-Frame-Options are often set globally for the entire application, this means that developers who have any resources that fall into this category will either see their sites break or will have to manually exempt some resources from From-Origin, which will complicate adoption and reduce the security value of using the mechanism in the first place.
Arguably, the sites that would benefit the most from From-Origin protections are the ones with large userbases, hosting sensitive authenticated content, which often have relatively complex cross-origin loading relationships. It seems to me there'd be a lot of value in making From-Origin work for them, or, if we decide against it, provide another mechanism they can use.
Could a combination of referrer and From-Origin same/same-site achieve the same level of flexibility? I.e. if you get no referrer, you send a From-Origin header. I guess not since the referrer conveys nothing about frame ancestors.
I definitely like the idea of letting the server make decisions based on the sender of the request, but that might be a better fit for Sec-Site because of the legacy problems with Referer partly discussed in https://github.com/whatwg/fetch/issues/700#issuecomment-382762249.
Specifically in this case if the application only sends From-Origin if there is no referrer then it's more likely that users with software that blocks/spoofs the Referer would break, because the site owner would not extensively test this case (since it's a behavior they wouldn't see by default).
A new issue came up in our discussions. Should blocks due to From-Origin be opaque to the loading document? For document loads, failing the load explicitly reveals the existence of the document, which may sensitive.
We could instead cancel the load, log a console message, and dispatch a DOM load event to the destination frame.
If so, should we be equally opaque about other subresource blocks due to From-Origin to make the behavior consistent? If not, an empty successful load might also reveal the existence of a document since we would instead emit an error if the resource type was different.
How does a network error reveal anything? It's the same error as a problem with TLS/DNS/CORS/etc. results in.
The iframe element doesn’t emit load errors. Instead, it loads empty and fires onload. I believe it’s an old security discussion where the “arbitrary load” capabilities of iframes and their ability to synthesize documents out of non-document responses were considered dangerous if an attacker can use onload/onerror to test for resource existence, perform multi step CSRF, or check victim privileges. Maybe someone else in this thread knows more?
Here’s an example of the discussion: https://bugs.chromium.org/p/chromium/issues/detail?id=365457
That's tracked in https://github.com/whatwg/html/issues/125 as well (though no security discussion there).
But it seems to me that if you don't get onload and it therefore fails equivalently to TLS/DNS/CORS errors there isn't much revealed, unless you somehow already knew it to exist, but then why wouldn't you know about From-Origin either?
Some Mozillians briefly discussed the code that landed in WebKit by the way and modulo the feedback above we're supportive of adding that to Firefox.
I can work out a more concrete proposal in the form of a PR next week I think. Is anyone willing to write web-platform-tests?
There are some tests available in WebKit that should be converted to WPT.
I guess this is on WebKit team plate.
There are some points that might be nice to iron out:
make deployment of From-Origin more difficult if there is no way to limit From-Origin check to the document and not the whole ancestor chain.
If all browsers ship process-isolation at the <iframe> boundary at some point this will also be a limitation of the feature that makes it harder for sites to use that want to be embedded as a widget. Perhaps we should consider a more complicated design: same/same-with-ancestors/same-site/same-site-with-ancestors. Or alternatively go back to the idea of requiring both From-Origin and X-Frame-Options to be specified. (If we include ancestor checking I think it should work identically to X-Frame-Options, including any referrer checks we may include there to avoid leaking the embedder.
I think failing for data: URLs (and sandboxed <iframe>s without same-origin) is fine. Making that work while still keeping things secure seems quite complex.
For service workers we could go through the ancestor chain of the clients that are currently active (I would expect this for dedicated and shared workers), but that would not be very deterministic. I guess that means that once you have a service worker you need to be careful about X-Frame-Options/From-Origin for resources that can be intercepted.
If all browsers ship process-isolation at the
Splitting the responsibility between From-Origin and X-Frame-Options has some benefits:
For service workers we could go through the ancestor chain of the clients that are currently active (I would expect this for dedicated and shared workers), but that would not be very deterministic. I guess that means that once you have a service worker you need to be careful about X-Frame-Options/From-Origin for resources that can be intercepted.
From spectre perspective, it all depends on how service workers are run. If a service worker runs in its own per-origin process, it is fine for the service worker to get access to the resource without checking potential ancestors, so long as the service worker applies the ancestor checks before sending the response to the final context process.
I think failing for data: URLs (and sandboxed
I kind of agree but would like to point out some points that feel somehow inconsistent:
I think if we're comfortable relying on both From-Origin and X-Frame-Options we could make From-Origin a part of CORB. It would then not affect CORS or navigation, but only cross-origin no-cors fetches.
I quite like that model as it gives sites small building blocks rather than a complete solution that might not work for them. It also makes all our various technologies piece together quite neatly.
cc @anforowicz
Or initial implementation is now out in Safari Technology Preview 56. Turn it on under Experimental Features.
https://webkit.org/blog/8296/release-notes-for-safari-technology-preview-56/
I chatted with @annevk a little this morning, and my understanding of his narrowing suggestion is the following:
from-origin would be folded into https://fetch.spec.whatwg.org/#corb-check as another way of triggering its blocking behavior.from-origin would apply only to cross-origin, no-cors requests. That is, it would cover things like <img>, <script>, etc, but developers would also need frame-ancestors or XFO for protection against embedding.Relatedly, I'm convinced by @arturjanc's argument here and elsewhere that interesting web applications with equally interesting cross-origin relationships are going to have a hard time deploying something like this unless we give them more flexibility than same and same-site. That concern is mitigated to some extent by limiting the header's effect to no-cors requests, but I don't think it's obviated, given things like JSONP endpoints that could use more granularity. I'd suggest that a list of origins (or sites) would be a reasonable mechanism to add to this header.
If we accept the above, then I think the Fetch spec change might look something like something like:
If request's origin is not same origin with request's current url's origin, and request's mode is
no-cors, and request's header list containsFrom-Origin:
- [Process
From-Originto get a list of origins (sites?)]- [If the header was invalid, continue.]
- [If request's origin is not contained in the list, return blocked]
Does that match your understanding, @annevk?
(And, since we're bikeshedding already, the name "From-Origin" seems overly broad if this is the model we're running with. CORB-Me-Unless-Im-Being-Requested-By: same-site is a terrible suggestion, I'm sure we can come up with more together. :nerd_face:)
Roughly, I think it could be part of the CORB check directly: https://fetch.spec.whatwg.org/#corb-check. (The only potential downside of that is that it would not apply to redirects.)
Roughly, I think it could be part of the CORB check directly: https://fetch.spec.whatwg.org/#corb-check.
Yes, sorry. I meant that pseudospec to be a new step 7 of the CORB check. Not applying to redirects would mean that redirect targets would be potentially revealed to the renderer process (at least in Blink, as we still do checks like CSP in the renderer: eventually it'll hop up to the browser, but it's a ton of work we haven't done yet). That might be a reasonable tradeoff against simplicity?
I see, the CORB check is only run for cross-origin "no-cors" responses so some of the conditionals can be removed.
I think From-Origin (or whatever we call it) should apply to redirect responses.
In WebKit we are moving redirect logic to the network process as much as possible, including moving relevant CSP checks there, so we would not want a remaining potential channel to leak redirect responses.
Some WebKittens talked about this and are agreeing on the following direction:
Is there consensus here?
To be noted that, if the check fails, WebKit will fail the load. IIANM, CORB is not doing so, probably to minimize breakage risks.
Given this header is opt-in, I have a slight preference to continue raising an error.
WebKit also currently checks this header for navigation loads. Some discussion might be good to decide whether doing navigation loads checks or not, cc @johnwilander.
I think
From-Origin(or whatever we call it) should apply to redirect responses.
I think this is a reasonable direction to move in. To the extent possible, we should give developers the ability to exclude redirect responses from potentially compromised cross-origin processes.
Some WebKittens talked about this and are agreeing on the following direction:
These seem reasonable from my perspective. Regarding "Support same/same-site values", though, I'd point again at @arturjanc's suggestion that same and same-site isn't going to be granular enough for applications with interesting cross-origin relationships.
To be noted that, if the check fails, WebKit will fail the load.
As you note, CORB does not fail the load, but instead delivers a filtered response. I don't have a strong feeling about which behavior we ought to end up with, but I do think that diverging would be confusing. I'd prefer for us to align the response that's returned from both From-Origin and CORB if we're going to fold their processing model together. My intuition is that that's simpler to do by treating both as network errors, but I'm curious about the error you're interested in raising, @youennf: would you prefer to raise a From-Origin-specific error? If so, why?
These seem reasonable from my perspective. Regarding "Support same/same-site values", though, I'd point again at @arturjanc's suggestion that same and same-site isn't going to be granular enough for applications with interesting cross-origin relationships.
It makes sense to make this header value consistent with other similar mechanisms.
I believe a list of origins is allowed in CSP frame ancestors.
If that is used in the wild, it makes sense to support multiple origins in this new header as well.
Conversely, we might envision supporting same-site in CSP frame ancestors.
@youennf: would you prefer to raise a From-Origin-specific error? If so, why?
A network error seems consistent with other fetch error handling.
It makes sense to make this header value consistent with other similar mechanisms. I believe a list of origins is allowed in CSP frame ancestors.
That's correct. Some browsers support a similar ALLOW-FROM mechanism in X-Frame-Options as well.
If that is used in the wild, it makes sense to support multiple origins in this new header as well.
I wouldn't tie the (non)sensicalness of granular control to frame-ancestor usage, but allow it to stand on its own. We have some fairly concrete claims from Google's application folks in this thread and elsewhere on Twitter that it would be hard to deploy From-Origin without such granularity. I'd suggest that it adds only marginal implementation complexity over and above same and same-origin, and seems to be well worth the tradeoff against deployment complexity.
Conversely, we might envision supporting same-site in CSP frame ancestors.
Some sort of alignment here seems like a reasonable idea; it does seem like a useful addition, though I'm not sure how to add it in a backwards-compatible way.
Cross-Origin-Resource-Policy is the name that got consensus within WebKit folks.
Plan is to update WebKit tests and implementation with that name.
Cross-Origin-Resource-Policy is the name that got consensus within WebKit folks.
Plan is to update WebKit tests and implementation with that name.
SGTM. Do y'all plan to write up the proposal as well? This thread is pretty convoluted, and I think it would be helpful to clarify things in an explainer/spec. :)
I drafted a proposal over at #733. It currently doesn't support origin values, but that'd be easy to add. It wasn't quite clear to me if there's agreement on that for v1.
FYI: the PR is pretty close to done. One final thing I'd like us to consider is whether we should add port restrictions to same site, as originally proposed by @jeisinger for a number of features (none for which it's been done thus far, mind).
The idea would be that request and response are only same site if either:
(I guess this puts a mild dependency on the scheme too.)
One final thing I'd like us to consider is whether we should add port restrictions to same site, as originally proposed by @jeisinger for a number of features (none for which it's been done thus far, mind).
Can you point to the initial proposal from @jeisinger or the potential use cases for this kind of restriction?
https://github.com/whatwg/html/issues/2792 (and there's also https://github.com/w3c/webauthn/issues/873, raised much later by me). The motivation isn't clearly stated there, but it's to reduce the impact of having a broader scope than the same-origin policy, which is the more fundamental security boundary, but tightening down the ports as well if at least is the default port.
@johnwilander mentioned the possibility to rename same to same-origin.
That might be easier to understand, would be closer to X-Frame-Options sameorigin...
Yeah, now the header name changed that makes sense to me. Happy to make that change tomorrow. Did @johnwilander have feedback on port restrictions?
OK, let's change it to same-origin then. I'll update the WPT tests.
As of port restrictions, @johnwilander had some questions related to the added complexity and impact on intranets.
It might be easier to tackle it as a separate issue.
The main reason I'm raising it here is that adding a further restriction later will be harder, once there's some adoption. But if nobody else feels strongly about it I guess I'll let it go.
The same/same-origin version clearly needs to enforce same port. For same-site, I am not sure. Since it already allows different hosts, it's not clear to me what the benefit would be of having any kind of port restriction. But on the other hand, custom ports are used rarely enough that it probably isn't very harmful either.
I'm trying to think of a scenario where it's ok to let http://a.example.com resources be accessed from http://b.example.com but not http://a.example.com:8080 and I can't think of an obviously problematic case.
well, i'm concerned about somebody managing to set up a rogue serer at a.example.com:8080 that can then grant access to resource on a.example.com
I want the header to be simple. Restricting ports is adding complexity and potential breakage to the same-site directive. For me, same-site means “It’s your domain. You are in control of its subdomains, schemes, and ports. You may have an unusual setup with your domain and that’s OK. This header will restrict to your domain but not break your custom setup.”
I’ve seen non-default ports used in intranets and I’ve even built a national healthcare system where we had to switch to 8443 for HTTPS to avoid having to give the cert’s private key to the firewall operators. HTTPS over 443 was on their list of traffic they had to monitor whereas our super sensitive patient information should absolutely not be monitored.
The same-site directive is not supposed to save you from not having control over your subdomains. A rogue evil.example.com server could most probably steal cookies through requests anyway. Instead, we should maximize the chance of same-site working so that as many orgs as possible can adopt it. (That’s also why I wanted it to work for all resource types but I lost that battle.)
well, i'm concerned about somebody managing to set up a rogue serer at a.example.com:8080 that can then grant access to resource on a.example.com
I am not sure how typical it is to not be able to control a.example.com:8080 if controlling a.example.com.
There is the potential use case of a public website hosted in 80/443 and the website admin hosted in different ports.
In that case, the port restriction for same-site might initially make sense for the public website.
But it might make more sense to have the website admin be marked as same-origin, in which case the public website could remain 'same-site'. Not checking the ports would allow the admin website to access public web site resources.
If we add support for a list of origins in the future, it is also somehow feasible to define same-site-with-port-check directly.
It makes sense to me that same-site would be agnostic to ports, i.e. http://foo.example.org:1234 would be same-site to http://bar.example.org:80.
However, it would be a problem to also ignore schemes because we very likely don't want http://foo.example.org:1234 to be same-site with https://bar.example.org. Otherwise, the header would offer no protection against attacks if the user is (or ever was) on a malicious network which injects a cached document over HTTP to attack unrelated HTTPS-based same-site applications.
My guess is that if this mechanism doesn't attempt to protect from such network-level attacks, it might reduce its appeal to developers because their sensitive applications hosted over HTTPS would no longer be guaranteed confidentiality. Also note that supporting origin values would be an easy solution to this problem because developers who have mixed content which would be blocked under the stricter logic could temporarily allow it to load by adding a corresponding http: entry in their headers.
That is solved by HSTS and if you use HTTPS without that, you're very much susceptible to attacks already. And since we cannot over anything better than HSTS, I'm not convinced it's worth adding an additional check at this layer for that concern.
I hear your concern, but there are two subtleties worth pointing out:
includeSubDomains -- otherwise an attacker can pick an arbitrary non-existent subdomain and get same-site access to the HTTPS application they want to attack. A large number of sites using HSTS do not set includeSubdomains (at first glance: HSTS on google.com, apple.com, mozilla.org, and microsoft.com does not have it, and neither do 3 of my favorite banks even though they all use HSTS). Perhaps Chrome has telemetry to disprove this in case it's just my sampling bias?X-Frame-Options: SAMEORIGIN or CSP 'self') and require explicit opt-in to all interactions with insecure content (e.g. if an HTTPS application wants to allow interactions from HTTP via postMessage or CORS it has to directly safelist the http: URL).I'm worried about creating a situation where insecurely delivered same-domain content will start getting special privileges to access data delivered over HTTPS -- it will make same-site interactions unsafe by default (unless they are coupled with site-wide enforcement of HTTPS, which is still rare).
I think that's a pretty good argument for also comparing the scheme. @youennf @johnwilander?
Including scheme or not in Same-Site is a tradeoff. Let me explain.
Attack target: Authenticated resources on https://bank.example
Attack scenarios:
OK, to defend against Spectre attacks, the bank wants to use Cross-Origin-Resource-Policy (formerly From-Origin).
If Cross-Origin-Resource-Policy: Same-Site ignores scheme, the second attack scenario is still possible whereas if Cross-Origin-Resource-Policy: Same-Site does consider scheme, both attack scenarios are covered.
However, including scheme makes Cross-Origin-Resource-Policy: Same-Site into a passive mixed content blocker. All legacy calls to images from http://*.bank.example will be blocked if the bank's servers always respond with Cross-Origin-Resource-Policy: Same-Site. This will make the bank less likely to deploy Cross-Origin-Resource-Policy which means _both_ attack scenarios are possible.
On intranets, man-in-the-middle attacks are not likely but old crufty http images are. We specifically want Cross-Origin-Resource-Policy to be a protection against Spectre attacks from open websites that pull in intranet resources.
Nit: it's same-site, case-sensitive, at least as currently proposed.
The attack can be a little more hidden. The attacker could rewrite the contents of blog.example to include a hidden iframe for bank.example and launch the attack from there while the user is reading blog.example (or they could rely on the user not noticing the address bar change and include the contents of blog.example on bank.example).
It's a fair point that it makes adoption and HTTPS migration trickier though.
I keep forgetting we no longer check the ancestor tree for Cross-Origin-Resource-Policy. Otherwise the sneaky, injected iframe would not have worked.
Just so that I have it stated here, I personally think we’ve step by step drifted away from a simple one-stop-shop protection we can evangelize to the long tail of sites during the year(s) where we figure out process isolation.
My initial implementation covered all resource types, all schemes and ports in one directive, and checked the ancestor tree. Such a header has a high likelihood of protection with low likelihood of misunderstandings or breakage IMHO.
Now developers need to understand non-CORS requests and deploy Origin checks, CSP frame-ancestors and Cross-Origin-Resource-Policy to protect all their resources. The same-site concept is only available in one of the three, increasing the likelihood of overlap, gaps, and inconsistent deployment.
I’m a little sad we ended up here. It feels like we’re piling on complexity where we should strive for simplicity.
Sorry for the rant.
I am not sure what is the easiest migration path. In the long run, I guess that both HSTS includeSubDomains and migration from HTTP to HTTPS resources will happen.
Since CORP: same-site derives from same-site cookies, what is same-site cookies doing in this particular case?
AIUI, same-site cookies is not checking the scheme.
If we summarize, the ideal same-site behavior would be:
@johnwilander the main reason I favor and I think we went with non-granular here is that all-encompassing solutions have a poor adoption rate due the complexity the overall web has reached. This is indeed unfortunate and it is forcing smaller sites to use some kind of abstraction, but adding something that does not work for many sites is not great either.
@youennf it's hard to compare with cookies since individual cookies have ways to limit themselves to HTTPS. document.domain basically does not work cross-scheme due to Mixed Content blocking. WebAuthn is limited to secure contexts.
As for the ideal behavior, the main problem with that is that if you try to migrate to HTTPS and were already using this header you now either need to remove this header or move cdn.example.com and example.com to HTTPS at the same time. (Or as @arturjanc suggests we add the same-scheme restrictions and also allow origins as values now and you could safelist http://example.com for a limited time while you migrate to HTTPS.)
@johnwilander the other thing I wanted to touch on, is that there's nothing stopping us from supporting a same-site value for Access-Control-Allow-Origin. There are some people not comfortable with increasing our reliance on the Public Suffix List, but it seems we keep breaching that dam anyway. But let's track that as a separate issue.
I plan on landing #733 (and tests) somewhere next week with no further changes (no scheme or port restrictions as per above discussion). I'll also look into adding more tests to cover the syntax particulars.
The current syntax might mean we cannot turn it into a structured header in the future (see https://github.com/httpwg/http-extensions/issues/629 for ongoing discussion), but it shares enough similarity with the syntax of CORS headers that I think we can have a shared parser regardless.
Now would be a good time for final appeals, though I’d be happy if we can call v1 done. 😊
LGTM to have this as v1.
I think we can continue the two items that are under discussion as follow-up issues.
Here is my personal thinking on the these two items.
Add a list of origins in addition to same-origin and same-site
This seems fine as long as it stays very simple, meaning simple string matching like done for ACAO for each origin.
Maybe same-site+a list of origins is something we could consider too, I am not sure.
Scheme checking for same-site
A no-cors HTTP resource loaded from an HTTPS context might remain popular and there are already ways to fix related security issues. It seems good to have CORP/same-site allowing it.
A no-cors HTTPS resource loaded from an HTTP context might not be as popular now and seems harmful, even in the long run. Maybe we can try disallowing this case.
Scheme checking for same-site
A no-cors HTTP resource loaded from an HTTPS context might remain popular and there are already ways to fix related security issues. It seems good to have CORP/same-site allowing it.
A no-cors HTTPS resource loaded from an HTTP context might not be as popular now and seems harmful, even in the long run. Maybe we can try disallowing this case.
I agree with Youenn here. The scheme-matching case that worries me the most is http images on https pages. We know it is a common scenario and we're struggling with how to evolve mixed content blocking in the same regard.
The reverse doesn't worry me as much, i.e. requiring a scheme match for https resources on an http page if the https resource says same-site. The resource is clearly more secure than the page and so its policy response should protect it from ending up in a non-secure context. The only downside I see there is increased complexity, similar to how the referrer header gets stripped in http-to-https transitions. Developers have struggled to understand that for two decades. :/
I was worried that might make it harder to transition to HTTPS, but since it's only same-origin/same-site that concern is likely overblown a bit. I'll write a test for that and update the standard PR accordingly.
I filed #760 on origin values.
Done, https://github.com/whatwg/fetch/issues/687#issuecomment-395366076 is still in effect, except that there is now a scheme restriction in one direction. I'd appreciate review on the added text and the new tests.
I looked at the spec changes in https://github.com/whatwg/fetch/pull/733 and they make sense to me. I also like @youennf's solution from https://github.com/whatwg/fetch/issues/687#issuecomment-394106967 to not relax the same-site restrictions to HTTP origins when loading HTTPS resources (but allow loads in the other direction).
LGTM overall for v1. I do think some developers may encounter problems during adoption due to the lack of origin-based granularity and not having sufficient visibility into who requests their resources, but this is likely something we can tackle in the future.
I tried to find bugs tracking implementation status in various browsers and this is what I came up with:
I hope that the list above is useful going forward (I wasn't able to find links to these bugs in the comments above).
I also looked at https://master-dot-wptdashboard.appspot.com/results/fetch/cross-origin-resource-policy?label=master&label=stable&aligned and I see that Safari passes most WPT tests for CORP, but is not yet at 100%. I don't know how to see details of the test results or how to locally/manually run the tests against Safari - I am not sure what the failures mean (incomplete implementation in Safari? test issues?
are these tracked in a separate bug?).
@anforowicz https://github.com/whatwg/fetch/pull/733#issuecomment-398055807 has links, which include https://bugs.webkit.org/show_bug.cgi?id=186761 for Safari which was supposed to track remaining failures. Perhaps those are only in Safari Technology Preview? Or perhaps new tests landed since then.
cc @youennf
script-loads.html, image-loads.html and fetch-in-iframe.html are running fine locally and using w3c-test.org for me. I do not know why they are not showing up as such in WPT.
fetch.any.js seems to be buggy with regards to same-site.
It seems that fetch.any.serviceworker.html is run over HTTPS while fetch.any.html is run over HTTP on w3c-test.org, which has an impact on same-site behavior.
I'll do a PR.
There are already extensions that e.g. disable X-Frame-Options; I worry that use of such would become
more widespread if CSP is seen as something that breaks the web - to no
security benefit for the user - by blocking third-party font and image loads.Only WPT failure seems to be related to case-insensitive comparison of the value. WebKit currently allows SAME-ORIGIN.
It does not seem that we have yet added tests for HTTP same origin loads from HTTPS contexts. We should probably be consistent no matter whether the load destination is Document or not.
I guess that we could either fail or return an empty response.
This seems to be a good topic to discuss in whatwg/fetch/github
Thanks
Security Advisor
@WPHH
Most helpful comment
I've been following this thread while on vacation and didn't have time to comment until now, but this is an important problem that I also feel strongly about solving (thank you @johnwilander for starting this discussion!). Since there are a lot of ideas here, I wanted to summarize the discussion as I understand it, and compare the benefits of the proposals that came up.
As background, in the past we've thought a fair amount about protecting applications from cross-origin information leaks -- allowing developers to prevent their applications' endpoints from being loaded as subresources of an attacker-controlled document goes far beyond protecting the exploitation of Spectre-like bugs, and can address a large number of cross-origin attacks we've seen over the past decade.
Specifically, having the browser refuse to load protected resources in the context of the attacker's origin/process, could help solve the following classes of issues: cross-site script inclusion (XSSI), cross-site search, CSS-based exfiltration, as well as Spectre. Telling the server about the requester's origin as Mike suggested above would also give developers the chance to prevent most kinds of attacks based on cross-origin timings and CSRF -- the server could be configured to only accept subresource requests coming from trusted origins.
For completeness, addressing these kinds of issues was part of the motivation for EPR and Isolate-Me, as well as for same-site cookies. But these proposals are fairly heavy-weight to implement and adopt, and there is value in having a simpler mechanism to tackle the classes of issues mentioned above.
IIUC the discussion here focused on two main alternatives:
From-Originresponse header as outlined in Anne's original proposal which would prevent the browser from exposing the contents of the response to non-safelisted origins.The first option is somewhat simpler and makes the protection more explicit; in some cases, developers might be able to set
From-Origin: sameon all responses and that would be sufficient to protect against Spectre and some cross-origin leaks. The second option requires more work on part of the server (adding logic to decide whether to respond to a request based on its sender), but it's more flexible and more powerful because it can also protect against CSRF and timing attacks, though with some caveats.As a data point from someone who works with a large number of non-trivial applications, I feel that it might be somewhat easier to adopt this if we go with option 2, possibly with a new request header, e.g.
Sec-Requesting-Origin-- we might not be able to reuseOriginbecause of backwards compatibility issues, though I'm not 100% sure about this. On the server side, the logic would boil down to checking if the header is present in the request, and if so, rejecting requests if the requesting origin isn't trusted (if there is no header, or the origin is trusted, return the response as usual).If browsers were to consistently set this header, developers could start by collecting data about origins which are already requesting authenticated resources from their application by collecting header values, and then turn on enforcement by returning empty responses if the requesting origin isn't trusted. This could also work even if there is a Referrer Policy of
no-referrerif we make the user-agent send a special identifier to include some coarse-grained information about the source (e.g.same-origin,same-siteorcross-siteas Mike suggested above). If we're worried about the number of bytes on the wire this would add to requests, it could be require an opt-in via an Origin Manifest or a header-based mechanisms similar to HSTS. Finally, we could also consider having a special way to annotate navigational requests to protect against the exploitation of CSRF via top-level navigations.I think this would be powerful enough to allow application developers to protect from Spectre, especially if combined with default protections via CORB, and would simultaneously allow developers to protect against other cross-origin leaks.
From-Originas originally described in Anne's doc seems workable as well, but is a little more constrained -- perhaps there really is value in doing both things?