W3C home > Mailing lists > Public > www-tag@w3.org > March 2016

Re: Comment on minutes ## With Credentials flag etc

From: Jonas Sicking <jonas@sicking.cc>
Date: Thu, 31 Mar 2016 10:50:07 -0700
Message-ID: <CA+c2ei_1vgFC0WuK0W4meZtJaoV67kic1zHwEsBqT6uxG08-XQ@mail.gmail.com>
To: Tim Berners-Lee <timbl@w3.org>
Cc: Mark Nottingham <mnot@mnot.net>, Public TAG List <www-tag@w3.org>
>> Q: Why are security checks performed when withCredentials is set to false?
>> A: Because the user, and the user's browser, might be behind a
>> firewall and so might be able to access servers which a website would
>> otherwise not be able to access.
>>
>> Sadly there is no, to me, known mechanism for detecting if a given
>> server is behind a firewall.
>
> That’s a long rathole but ...
> 1) If your local IP address is the same as the one you get from a public IP reflector then you are not behind a firewall
> 2) If your IP address starts with 192.168… then you are behind a firewall …
> 3) BUT that isn’t the point, you can be outside a firewall and still have privileged access by your IP address.
> 4) And you could also be behind a carrier-grade NAT box but not have any privilege access as a result.
>
> One possible but hard route is to pursue something like the router telling your machine whether it has no privileged access, which would then enable a lot of stuff.  So public internet spaces would set the flag, which would then mean the browsers would do less preflights, wasted attempts to access stuff, etc and so the browser would run more quickly for less bandwidth.

If we get to a point where clients can reliably tell if a given
request goes to a server that is behind a firewall or not, then we
should certainly take advantage of that.

>> Q: Why does CORS not allow "Access-control-allow-origin: *" together
>> with withCredentials=true?
>> A: It was felt that this was too big of a foot gun.
>>
>> CORS was designed not long after Adobe had added the crossdomain.xml
>> feature to Flash Player. The crossdomain.xml feature allows webserver
>> administrators to easily indicate that the server contains resources
>> that should be loadable from other origins. The feature only allowed
>> "normal" requests, i.e. requests similar to ones that CORS makes when
>> withCredentials=true.
>>
>> When crossdomain.xml was released many websites opted in allowing data
>> to be read from other websites in order to share some public data that
>> was hosted on the server. Unfortunately they forgot that some other
>> URLs on the server served sensitive user data. The result was that
>> relatively quickly after the release of the crossdomain.xml multiple
>> websites leaked sensitive user data.
>>
>> You could argue that the problem was that crossdomain.xml was
>> different since it is a per-server configuration file, whereas CORS
>> uses per-URL headers. Hence CORS would be less prone to server
>> administrators accidentally opting in to sharing on URLs that server
>> user sensitive data.
>>
>> However in practice many (most?) popular web servers allow adding
>> configuration files which add static http headers to all URLs under a
>> given directory. So in practice on many servers it would have been
>> just as easy to make the same mistake with CORS.
>
> Any arguments about making things easy or difficult for server admins to
> shoot themselves is protecting the (server) user from themselves which should always be done with care.
> The user is the most important.

Absolutely. The current CORS design was done after a lot of web
administrators which deployed crossdomain.xml did so in a manner that
leaked sensitive user data to anyone with a website.

> To first order, the system must implement a security protocol which allows
> people to do the right thing — to give the right access to the right resources
> by the right people and origins.  Yes, by all means allow the server to protect data
> by default, but make it clear what is happening and allow the server operator easily to
> tell the server what the situation is.  (you are/not running on the open internet.  This information itself is/not quite public)
>
> When you make something impossible using HTTP in the browser, that is a big deal.

Yup. Though as far as I can tell, none of the use cases discussed so
far is impossible with CORS. In fact, we worked quite hard to make all
of HTTP accessible in even the initial release of CORS, despite the
fact the by far most common use cases only use a small subset of HTTP.

> Q: Why was reflecting the incoming origin in the header the thing which was picked
> as the way of saying “yes this really is public”?  Why not “access-control-allow-origin **” or something
>  It is a pain to code, needs two or three lines of not-newbie-obvious .htaccess in Apache, etc.

The main reason that reflecting the origin was chosen was so that an
intermediate cache wouldn't cause the browser to see the signal "yes
this is a public resource".

> Result? the recipe for fixing it is sent around to do the origin reflection, and new server code does it by default for everything.
> Because CORS is such a pain for developers to deal with on the client side, with no error codes, etc
> that servers who want stuff to just work, and slap in the strongest CORS medicine they find on the net.

I've never heard of servers doing this origin-reflection by default.
If that really is the case then I agree that that would be very
concerning since it would put us in an even worse state than
crossdomain.xml was in.

>> Q: Why does CORS not allow listing multiple origins, or allow pattern
>> matching, in the "Access-control-allow-origin" header?
>> A: It was felt that if the server uses dynamic server-side logic to
>> generate responses for a given URL, that they could also then
>> dynamically generate the appropriate Access-control-allow-origin
>> header.
>> For servers that generate static responses you can generally simply
>> use "Access-control-allow-origin: *”.
>
> Well no, not if they only want 7 specific domains to have access.

If the response is entirely static, and the server is connected to the
public internet, then there is little benefit to limiting the response
to 7 specific domains.

In practice such a response is world readable anyway since anyone in
the world could use curl or wget to read the data. No matter what is
sent in any CORS headers.

>> Keep in mind that static
>> responses can generally be read from non-browser HTTP clients like
>> curl anyway.
>>
>> This doesn't account for static responses which are password protected
>> using either cookies or auth headers. So yeah, our solution here is
>> not perfect, but we decided to opt for simplicity.
>>
>> My personal hope was also that generic server modules would be written
>> to handle CORS support and which would simplify situations like this.
>> I'm not sure if such modules exist yet or not.
>
> There are lots. They may be turned on by default.  A concern is they tend to just defeat CORS
> and they don’t necessarily distinguish between public resources and others.
>
> Also people use CORS proxies to access the web, which are associated

Does anyone have any examples of websites that have shared data that
should have been kept private publicly?

We saw plenty of examples where that happened with crossdomain.xml,
but I've personally not heard that it's happened with CORS. But
absence of evidence is not evidence of absence, so I'd be very
interested to hear about any breaches.


> I think the top three issues the TAG had were basically
>
> a) Having the withCredentials flag as a parameter to fetch() is broken.  In general the middleware which calls fetch() will not have magic application-level knowledge of which resources it is going to fetch are public, which are private.   So a general the fetch has to work without that hint, and do the right thing. (opinions vary here)

As was requested in
https://github.com/w3ctag/spec-reviews/issues/76#issuecomment-183317897
CORS enables a mode where you don't have to have any knowledge about
what the security policy of the server is, and you only have to define
a URL. CORS then adapts the wire protocol in order to make that safe.

The way that you do this is that you always set the withCredentials
flag to true. Then, as wire protocol you send the
access-control-with-credentials and access-control-allow-origin
headers with the appropriate values.

> b) For a webapp which needs to load stuff from the net, the lack of clear error conditions makes it hard to understand what is going on.
> c) Asking server writers to do the origin reflection thing is unreasonable

I suggest that the TAG work with the webappsec WG in order to come up
with concrete proposals for these two. That way we can compare
security aspects, wire protocols, performance, etc.

/ Jonas
Received on Thursday, 31 March 2016 17:51:16 UTC

This archive was generated by hypermail 2.4.0 : Friday, 17 January 2020 22:57:13 UTC