This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 26556 - Fetch and CORS inconsistent regarding TLS client authentication and Access-Control-Allow-Credentials
Summary: Fetch and CORS inconsistent regarding TLS client authentication and Access-Co...
Status: RESOLVED FIXED
Alias: None
Product: WHATWG
Classification: Unclassified
Component: Fetch (show other bugs)
Version: unspecified
Hardware: PC Windows NT
: P2 normal
Target Milestone: Unsorted
Assignee: Anne
QA Contact: sideshowbarker+fetchspec
URL:
Whiteboard:
Keywords:
Depends on: 21013 23706
Blocks:
  Show dependency treegraph
 
Reported: 2014-08-12 00:52 UTC by Ryan Sleevi
Modified: 2015-09-28 08:42 UTC (History)
8 users (show)

See Also:


Attachments

Description Ryan Sleevi 2014-08-12 00:52:52 UTC
I wasn't sure if this was intentional or not, and could not find discussion on the mailing list regarding this.

The W3C CORS doc ( http://www.w3.org/TR/cors/ ) defines "user-credentials" as
- cookies, HTTP authentication, and client-side SSL certificates that would be send based on the user agent's previous interactions with the origin ( http://www.w3.org/TR/cors/#user-credentials )

Per "Cross-Origin Request with Preflight", the Preflight request should "Exclude User Credentials" ( http://www.w3.org/TR/cors/#cross-origin-request-with-preflight-0 ) when making the OPTIONS request. 

This part largely aligns with the Fetch "CORS preflight fetch" at http://fetch.spec.whatwg.org/#cors-preflight-fetch

However, with respect to performing a CORS preflight fetch, it seems to make no attempt to ensure that a previously authenticated TLS connection is not used (e.g. in the case of HTTP keep-alive, for which the same issue applies to cases where using an HTTP Auth method that is channel/connection based, like Kerberos/NTLM), nor is a previously authenticated TLS session used (in the case of TLS session resumption)

This creates a situation where a preflight request - or an actual request - may carry over ambient authority (via the connection) that would otherwise be prevented (by virtue of Access-Control-Allow-Credentials ).

Is this an intentional change in Fetch?
Comment 1 Anne 2014-08-12 07:28:10 UTC
See http://lists.w3.org/Archives/Public/public-webappsec/2014Jan/0055.html and http://lists.w3.org/Archives/Public/public-webapps/2013AprJun/thread.html#msg487

It is not intentional. I'm not sure how to spell this out in a way that makes sense.
Comment 2 Anne 2014-08-12 08:27:44 UTC
There's also bug 21013 and bug 23706 regarding authentication.
Comment 3 Ryan Sleevi 2014-08-12 20:59:55 UTC
(In reply to Anne from comment #2)
> There's also bug 21013 and bug 23706 regarding authentication.

Right, I saw the bugs, but they seemed scoped to HTTP auth, and seemed some degree of intentionality, which is why I wanted to file this on TLS client auth.

For the record, Chrome behaves similar to Jonas' remarks regarding Gecko, which is Chrome has a concept of 'privacy mode', which is really "do not send cookies" mode.

For requests marked that they shouldn't send cookies, we (Chrome):

1) Don't share socket-level pools between the requests
  - This prevents reusing connections which were used to send previous requests with cookies, but does NOT prevent reusing connections between other such 'don't send cookies' requests
  - This includes SPDY/HTTP/2/QUIC connections
2) Don't share SSL session caches between the requests
3) Don't share TLS client auth state between the requests
  - Most UA's "cache" that a user has selected a particular certificate for a particular request, and when establishing new connections to that server, if it requests a certificate again, will continue to send that same certificate. This is conceptually similar to an HTTP auth cache, but the implementation differs a little. The point is, we don't share that
4) Don't share channel IDs (which are used to bind/protect cookies)

However, I'm actually uncertain of the state for our HTTP auth cache (mostly just because I'm not that familiar with a code, and test cases work better than code in most browsers these days)

I think that Fetch may need to say more about the connection establishment logic/transport level semantics, as undesirable as that may be. For future compat, it may be best specified as "Here's the things you shouldn't do", so that new technologies (such as SPDY / HTTP/2) can still comply with the spirit, even though the transport is different.

I do think Chrome's "privacy mode" of no cookies is not the right layer to embody in the spec - it was just a side-effect in Chrome that brought better spec compliance. But you can likely talk in terms of connection establishment and transport selection when talking about creds, to ensure no connection with pre-established creds are used.
Comment 4 Anne 2014-08-13 11:40:08 UTC
So yes, this affects how we define request's "credentials mode" in general. And in particular at the network & cache layer where it is most relevant. And whether or not that is impacted by HTTP authentication.
Comment 5 Anne 2014-11-03 11:20:08 UTC
Ryan, I have some questions.

1) Is socket-level pools grounded somewhere in a specification?

2) What is an SSL session cache? https://tools.ietf.org/html/rfc5077 perhaps?

3) TLS client auth certificate is the kind of stuff that comes from <keygen>, right? E.g. what StartSSL uses?

4) Where are channel IDs defined?

My tentative plan is to split out "If response is null, set response to the result of making an HTTP request, ..." from https://fetch.spec.whatwg.org/#http-network-or-cache-fetch and make that its own "Network fetch" section or some such where I define all these constraints.

/credentials flag/ can then be used to put requests in the correct bucket.
Comment 6 Ryan Sleevi 2014-11-03 22:17:24 UTC
(In reply to Anne from comment #5)
> Ryan, I have some questions.
> 
> 1) Is socket-level pools grounded somewhere in a specification?

http://tools.ietf.org/html/rfc2616#section-8.1
http://tools.ietf.org/html/draft-ietf-httpbis-http2-15#section-9.1.1

Probably more, but those are likely most relevant.

> 
> 2) What is an SSL session cache? https://tools.ietf.org/html/rfc5077 perhaps?

The set of session identifiers that a client is willing to use to negotiate the use of previously negotiated security parameters.

http://tools.ietf.org/html/rfc5246#section-7.4.1.2

Session caches as a concept also applies to the client's TLS session ticket rules (RFC 5077)

> 
> 3) TLS client auth certificate is the kind of stuff that comes from
> <keygen>, right? E.g. what StartSSL uses?

No. <keygen> is NOT normatively spec'ed to have any behaviours with respect to client certs. It does, but that's not a normative requirement.

It's not specified in any spec. It's something user agents do because they often need to make multiple TLS connections to the same endpoint. If the TLS server requests a client certificate ( http://tools.ietf.org/html/rfc5246#section-7.4.4 ), the UA may determine that it has previously decided what certificate to send (e.g. by prompting the user, through pre-configured policy, etc). Rather than re-prompting the user/consulting policy, it will use the previously determined client certificate on the new TLS connection.

Think of it the same as the HTTP authentication cache that nearly every UA implements (since auth was supposed to be per-Request, although ignoring NTLM/Negotiate's violation of this), except extrapolated to "per-TLS handshake" (since not every server may support session resumption, whether session ID or session ticket based)

> 
> 4) Where are channel IDs defined?

http://tools.ietf.org/html/draft-balfanz-tls-channelid-00 was the old (and expired) spec.
http://tools.ietf.org/html/draft-balfanz-https-token-binding-00 is the new spec (being presented at IETF 91)

> 
> My tentative plan is to split out "If response is null, set response to the
> result of making an HTTP request, ..." from
> https://fetch.spec.whatwg.org/#http-network-or-cache-fetch and make that its
> own "Network fetch" section or some such where I define all these
> constraints.
> 
> /credentials flag/ can then be used to put requests in the correct bucket.

I guess there's still some question as to whether or not it's "correct" to bucket these in the same bucket as credentials. I believe Takeshi has thoughts on this matter, per the previous discussion (c.f. https://lists.whatwg.org/pipermail/whatwg-whatwg.org/2014-August/297443.html )
Comment 7 Anne 2015-01-20 09:49:03 UTC
Yeah per https://lists.w3.org/Archives/Public/public-whatwg-archive/2014Aug/thread.html#msg82 (list archives moved due to HSTS mistake) Takeshi would weigh in here. Still have no better plan than comment 5.
Comment 8 Takeshi Yoshino 2015-01-21 13:13:53 UTC
As I stated in [1], in the first place, I don't quite understand why the various kinds of "credentials" are just omitted for preflight requests.

The only clear reason I could find is the text "Why can cookies and authentication information ..." introduced into the CORS spec by [2] (2008/Jan/18). We shouldn't allow scripts (origin X) to provide credentials (user/pass, etc.) for cross-origin requests (to origin Y). This was first taken care of by the text "No credentials, entity body, et cetera are to this request." introduced into the CORS spec by [3] (2008/Jul/07) (and announcement by Anne [4]) but only for preflight requests. It seems we should also omit any script authored credentials for simple cross-origin requests. But it didn't happen.

I cannot find any minutes of 2008 Seattle F2F, so just guessing, but it seems [3] just introduced credentials opt-in mechanism and it wasn't intended to address the security considerations added by [2].

The security consideration text disappeared on [5] (2009/Feb/24) without addressing the issue for simple cross-origin requests. On 2010/Feb/17, [6] has finally introduced the requirement into the XHR2 spec. It was lost from the XHR spec on [7] (2012/Oct/11). The Fetch Standard doesn't take care of this.

So, I think
- Things have been broken in the long history.
- We don't know any concrete reason / attack vector to address by excluding non-script-authored(controllable/alterable) "credentials".
- Even for simple cross-origin requests, any script-authored "credentials" should be omitted.

By quickly studying what the Token Binding is, I guess it's fine to send it on a preflight request. Using the same connection (even over TLS), sending cookies that are stored in UA and not controllable by the script, etc. etc. are all fine as far as it's impossible to abuse them for dictionary attack, I think. I.e. whether preflight with the "credentials" is useful for attackers compared to preflight without the "credentials".

----

Another bucket is one for using withCredentials system. Same as the above discussion, I don't know the original motivation for withCredentials.

withCredentials was introduced to the XHR-2 spec by [8] from AC spec (CORS spec) [9]. The base idea was introduced to the AC spec by [3].

I'd like to ask Anne to share the original ideas behind the introduction of the credentials flag. Based on that, what to put into the bucked could be determined. Attackers can always choose more powerful one. So, we should think of "how much credentials we can allow XHR/Fetch users to include", ... and if there was any ideas to allow normal users to limit credentials to send, then we should also think of "what normal user expects for withCredentials=false".

----

[1] https://lists.w3.org/Archives/Public/public-whatwg-archive/2014Aug/0083.html
[2] http://dev.w3.org/cvsweb/2006/waf/access-control/Overview.src.html.diff?r1=1.131;r2=1.132;f=h
[3] http://dev.w3.org/cvsweb/2006/waf/access-control/Overview.src.html#rev1.181
[4] https://lists.w3.org/Archives/Public/public-webapps/2008JulSep/0033.html
[5] http://dev.w3.org/cvsweb/2006/waf/access-control/Overview.src.html?f=h;rev=1.228
[6] http://dev.w3.org/cvsweb/2006/webapi/XMLHttpRequest-2/Overview.src.html#rev1.90
[7] https://github.com/whatwg/xhr/commit/08fb7d6b1d0d28116710e9db231e709b3890fca3
[8] http://dev.w3.org/cvsweb/2006/webapi/XMLHttpRequest-2/Overview.src.html#rev1.34
[9] http://dev.w3.org/cvsweb/2006/waf/access-control/Overview.src.html?f=h;rev=1.189
Comment 9 Anne 2015-01-28 10:32:29 UTC
At the time there was a lot of opposition to sending credentials across origins, even though there was established precedent with <img> and <form> and such.

https://lists.w3.org/Archives/Public/public-webapps/2009AprJun/thread.html#msg818 captures some of that debate.

That is why I think we made the decision to not send credentials across origins by default. And we never send credentials for the preflight because a) it's not needed and b) it would be a new attack vector as the preflight uses a different HTTP method.


> Even for simple cross-origin requests, any script-authored "credentials"
> should be omitted.

I don't understand what you mean by 'script-authored "credentials"'. As far as I know we do omit credentials by default under "cors".
Comment 10 Takeshi Yoshino 2015-01-28 11:37:25 UTC
(In reply to Anne from comment #9)
> At the time there was a lot of opposition to sending credentials across
> origins, even though there was established precedent with <img> and <form>
> and such.
> 
> https://lists.w3.org/Archives/Public/public-webapps/2009AprJun/thread.
> html#msg818 captures some of that debate.
> 
> That is why I think we made the decision to not send credentials across
> origins by default. And we never send credentials for the preflight because
> a) it's not needed and b) it would be a new attack vector as the preflight
> uses a different HTTP method.

Thank you. I'll take a look at it.

> > Even for simple cross-origin requests, any script-authored "credentials"
> > should be omitted.
> 
> I don't understand what you mean by 'script-authored "credentials"'. As far
> as I know we do omit credentials by default under "cors".

In the old CORS spec,

http://dev.w3.org/cvsweb/2006/waf/access-control/Overview.src.html.diff?r1=1.131;r2=1.132;f=h

You can find this item in the FAQ:

> Why can cookies and authentication information not be provided by the script author for the request?
> 
> This would allow dictionary based, distributed, cookies / user credentials search.

By 'script-authored "credentials"', I meant this. Does this concern apply only to non-simple cross-origin requests?
Comment 11 Anne 2015-01-28 11:41:43 UTC
That concern is no longer applicable. We don't allow control over cookies due to the complexity of separating cookies that are HttpOnly from those that are not. We allow setting the Authorization header, but it does require a preflight (due to the header not being whitelisted).
Comment 12 Takeshi Yoshino 2015-01-28 11:48:46 UTC
(In reply to Anne from comment #11)
> That concern is no longer applicable. We don't allow control over cookies
> due to the complexity of separating cookies that are HttpOnly from those
> that are not. We allow setting the Authorization header, but it does require
> a preflight (due to the header not being whitelisted).

Oh, got it. How about username:password in the URL? The Authorization header generation step lives in the "HTTP network or cache fetch" algorithm. At that point, we've already computed simple/non-simple (which lives in the "HTTP fetch" algorithm).
Comment 13 Takeshi Yoshino 2015-01-28 11:51:11 UTC
Ah. authentication fetch flag is not set for XHR and fetch()?
Comment 14 Anne 2015-01-28 12:02:55 UTC
(In reply to Takeshi Yoshino from comment #12)
> How about username:password in the URL?

We never get there for "cors".

> The Authorization header
> generation step lives in the "HTTP network or cache fetch" algorithm. At
> that point, we've already computed simple/non-simple (which lives in the
> "HTTP fetch" algorithm).

The user agent setting the header is different from script setting the header. I agree this is confusing, if there's a web-compatible way to make this saner I'm open to suggestions, but I thought these were the constrains we have.


(In reply to Takeshi Yoshino from comment #13)
> Ah. authentication fetch flag is not set for XHR and fetch()?

The authentication fetch flag is an internal detail of the algorithm. Do you mean the authentication flag? That is set for XMLHttpRequest, but not for fetch().
Comment 15 Takeshi Yoshino 2015-01-28 13:34:41 UTC
(In reply to Anne from comment #14)
> The authentication fetch flag is an internal detail of the algorithm. Do you
> mean the authentication flag? That is set for XMLHttpRequest, but not for
> fetch().

Right. Sorry for taking your time. I didn't look at how "authentication fetch flag" is set carefully.

Now my understanding is:

The only step which sets "authentication fetch flag" is run only after the fetch algorithm sees 401, and the step doesn't run when the "CORS flag" is set, and therefore the step in the "HTTP network or cache fetch" algorithm which generates "Authorization" from URL is never run for CORS.

Is this correct?
Comment 16 Anne 2015-01-28 13:42:48 UTC
Yes. It can only happen if there's an authentication entry (and credentials is enabled) or if the script set the header.
Comment 17 Takeshi Yoshino 2015-01-28 13:56:18 UTC
OK. Now I understood that abuse for distributed credential search is no longer concern. Thank you so much.
Comment 18 Anne 2015-02-17 16:54:06 UTC
I added some text to the specification that reinstates the request grouping around the credentials flag:

https://github.com/whatwg/fetch/commit/44546f2f850bdd49bd08d44ce68188b9ba239a93

Does this seem about right for now?