Tainted Origin Flag

35 views
Skip to first unread message

Nicolás Peña

unread,
Oct 31, 2019, 12:05:02 PM10/31/19
to Chromium Loading Performance, Yutaka Hirano, hiro...@chromium.org, Yoav Weiss
Hi! I'm looking to integrate ResourceTiming's TimingAllowOrigin (TAO) check into the fetch spec, and make it as close as possible to the CORS check. The plan in the future is to make TAO a subset of CORS.

I noticed that in the CORS check here https://fetch.spec.whatwg.org/#concept-cors-check we only accept '*' or 'null' when the tainted origin flag (https://fetch.spec.whatwg.org/#concept-request-tainted-origin) is set. Can anyone help me understand what are the security reasons behind this? annevk@ mentioned the confused deputy attack in the conversation in my pull request but I'm not sure I understand. This will help inform whether it makes sense to also have this in the TAO check. Thanks!

Yutaka Hirano

unread,
Nov 1, 2019, 1:42:48 AM11/1/19
to Nicolás Peña, Chromium Loading Performance, Hiroshige Hayashizaki, Yoav Weiss
Let A and B be web origins.
A/stash.cgi?key=<KEY>&value=<Value> stores KEY and VALUE to the storage in the server. This is a service only for the origin A, so it attached 'access-control-allow-origin: A' to the response.
If B/redirect.html, called from A and redirects to A/stash.cgi?key=foo&value=bar, had origin "A", then that request would pass the CORS check whereas "foo" and "bar" are chosen by B.

I think that's why tainted-origin flag exists. I don't know if TAO *has to* have a similar rule from security POV, but I think having a similar rule is good for understandability.

I have another question. Currently TAO is required for any cross-origin requests, but is it possible to allow accessing timing information without TAO for CORS checked requests?

Thanks,

Nicolás Peña

unread,
Nov 1, 2019, 10:23:03 AM11/1/19
to Yutaka Hirano, Nicolás Peña, Chromium Loading Performance, Hiroshige Hayashizaki, Yoav Weiss
On Fri, Nov 1, 2019 at 1:42 AM Yutaka Hirano <yhi...@chromium.org> wrote:
Let A and B be web origins.
A/stash.cgi?key=<KEY>&value=<Value> stores KEY and VALUE to the storage in the server. This is a service only for the origin A, so it attached 'access-control-allow-origin: A' to the response.
If B/redirect.html, called from A and redirects to A/stash.cgi?key=foo&value=bar, had origin "A", then that request would pass the CORS check whereas "foo" and "bar" are chosen by B.

Oh that's a good simple explanation, thanks!
 
I think that's why tainted-origin flag exists. I don't know if TAO *has to* have a similar rule from security POV, but I think having a similar rule is good for understandability.

Indeed it's unclear if it has to, though we intend to align it more with CORS in the future so I suspect it wouldn't harm much to add that rule.
 
I have another question. Currently TAO is required for any cross-origin requests, but is it possible to allow accessing timing information without TAO for CORS checked requests?

Currently, TAO and CORS are independent. You need TAO to get precise timing information, regardless of whether the resource was fetched with CORS or not. But this is part of why we're aligning TAO more and more with CORS! In the future, we'd like to propose something along the lines of "CORS implies that the TAO check passes". Doing this would greatly increase the number of resources that pass TAO, as CORS headers are more common (TAO headers only affect visibility into performance).

Yoav Weiss

unread,
Nov 2, 2019, 12:43:54 PM11/2/19
to Nicolás Peña, Yutaka Hirano, Chromium Loading Performance, Hiroshige Hayashizaki, Yoav Weiss
On Fri, Nov 1, 2019 at 3:23 PM Nicolás Peña <n...@chromium.org> wrote:

On Fri, Nov 1, 2019 at 1:42 AM Yutaka Hirano <yhi...@chromium.org> wrote:
Let A and B be web origins.
A/stash.cgi?key=<KEY>&value=<Value> stores KEY and VALUE to the storage in the server. This is a service only for the origin A, so it attached 'access-control-allow-origin: A' to the response.
If B/redirect.html, called from A and redirects to A/stash.cgi?key=foo&value=bar, had origin "A", then that request would pass the CORS check whereas "foo" and "bar" are chosen by B.

Oh that's a good simple explanation, thanks!

Indeed. Thanks, Yutaka! :)

In this case, IIUC, the Fetch spec requires that A would include "ACAO: *" if it wants redirects through B to work.
Is that correct? If so, do you know if there's any reason why "ACAO: B" or "ACAO: A,B" shouldn't work as well?

Dominic Farolino

unread,
Nov 3, 2019, 7:20:17 PM11/3/19
to Yoav Weiss, Nicolás Peña, Yutaka Hirano, Chromium Loading Performance, Hiroshige Hayashizaki, Yoav Weiss
> I noticed that in the CORS check here https://fetch.spec.whatwg.org/#concept-cors-check we only accept '*' or 'null' when the tainted origin flag (https://fetch.spec.whatwg.org/#concept-request-tainted-origin) is set.

Just to clarify, I believe the UA will accept the '*' header value (i.e., CORS check returns success) regardless of the tainted origin flag, right? However, it seems it will only accept 'null' when request's serialized origin is 'null', which is only the case when the tainted origin flag is set, as you mentioned.

> If B/redirect.html, called from A and redirects to A/stash.cgi?key=foo&value=bar, had origin "A", then that request would pass the CORS check whereas "foo" and "bar" are chosen by B.

Just for clarity, I believe in this scenario,the "foo" and "bar" pair tainted by B will still be stored to A's stash regardless of the failed CORS check. CORS and the tainted origin flag will only prevent tainted responses from being exposed to application code, but the request can still be made. For example, see https://origin-a.glitch.me/use-stash.html. You can see that when you write to the stash, if the request is tainted by B along the way, the response is unreadable, however when you read from the stash, it is clear the stash was still affected.

> In this case, IIUC, the Fetch spec requires that A would include "ACAO: *" if it wants redirects through B to work.
Is that correct? If so, do you know if there's any reason why "ACAO: B" or "ACAO: A,B" shouldn't work as well?

That's correct, origin A would have to include ACAO: * for redirects through B to work. ACAO: B would not suffice because even though the request was tainted only by B here, all the “tainted origin flag” keeps track of is that the request was indeed tainted at some point. It doesn’t know how many origins tainted it. E.g., a request could have the path A -> B -> C -> A. In this case it was tainted by B and C, and the ACAO header doesn’t have the ability to express more than one explicitly-allowed origin.

I imagine if we replaced the tainted origin flag with a tainted origin set (indicating a set of origins that tainted a request), and gave ACAO the ability to express “I'm OK with the set of origins {B, C, ...} tainting requests that end up at me”, then "ACAO: X,Y,Z" would suffice as you mentioned, but I guess that header's syntax doesn't support it.

--
You received this message because you are subscribed to the Google Groups "loading-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to loading-dev...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/loading-dev/CAL5BFfX6dKUaH%3DFrBi6mv5hqK3WMpuSNT2KwjU3JhvFFwdEbWw%40mail.gmail.com.

Yoav Weiss

unread,
Nov 4, 2019, 12:35:10 AM11/4/19
to Dominic Farolino, Yoav Weiss, Nicolás Peña, Yutaka Hirano, Chromium Loading Performance, Hiroshige Hayashizaki, Yoav Weiss
On Mon, Nov 4, 2019 at 1:20 AM Dominic Farolino <d...@chromium.org> wrote:
> I noticed that in the CORS check here https://fetch.spec.whatwg.org/#concept-cors-check we only accept '*' or 'null' when the tainted origin flag (https://fetch.spec.whatwg.org/#concept-request-tainted-origin) is set.

Just to clarify, I believe the UA will accept the '*' header value (i.e., CORS check returns success) regardless of the tainted origin flag, right? However, it seems it will only accept 'null' when request's serialized origin is 'null', which is only the case when the tainted origin flag is set, as you mentioned.

> If B/redirect.html, called from A and redirects to A/stash.cgi?key=foo&value=bar, had origin "A", then that request would pass the CORS check whereas "foo" and "bar" are chosen by B.

Just for clarity, I believe in this scenario,the "foo" and "bar" pair tainted by B will still be stored to A's stash regardless of the failed CORS check. CORS and the tainted origin flag will only prevent tainted responses from being exposed to application code, but the request can still be made. For example, see https://origin-a.glitch.me/use-stash.html. You can see that when you write to the stash, if the request is tainted by B along the way, the response is unreadable, however when you read from the stash, it is clear the stash was still affected.

> In this case, IIUC, the Fetch spec requires that A would include "ACAO: *" if it wants redirects through B to work.
Is that correct? If so, do you know if there's any reason why "ACAO: B" or "ACAO: A,B" shouldn't work as well?

That's correct, origin A would have to include ACAO: * for redirects through B to work. ACAO: B would not suffice because even though the request was tainted only by B here, all the “tainted origin flag” keeps track of is that the request was indeed tainted at some point. It doesn’t know how many origins tainted it. E.g., a request could have the path A -> B -> C -> A. In this case it was tainted by B and C, and the ACAO header doesn’t have the ability to express more than one explicitly-allowed origin.

OK, so as I suspected, there's no security consideration in blocking it, but a spec/implementation complexity one.
 

I imagine if we replaced the tainted origin flag with a tainted origin set (indicating a set of origins that tainted a request), and gave ACAO the ability to express “I'm OK with the set of origins {B, C, ...} tainting requests that end up at me”, then "ACAO: X,Y,Z" would suffice as you mentioned, but I guess that header's syntax doesn't support it.

Oh, I was under the impression that ACAO allows a list of `origin-or-null`s, but you're right and that's not the case.
At least for TAO, that's a useful feature, used by a good chunk of pages Chrome sees. 

Reply all
Reply to author
Forward
0 new messages