Re: Comment on minutes ## With Credentials flag etc

John Kemp <[email protected]> Tue, 19 Apr 2016 15:27:00 -0400
Newsgroups gmane.org.w3c.tag
Message-ID <[email protected]>
Hi Brad,

Just to mention a piece of (long-ago!) history related to CORS and XHR, =
as I previously did some TAG analysis on CORS and a related/competing =
proposal, called UMP, in relation to XHR.

https://www.w3.org/2001/tag/2010/06/01-cross-domain.html

There are a number of references listed there which may be helpful in =
your write-up.

Regards,

- johnk


> On Apr 19, 2016, at 12:52 PM, Brad Hill <[email protected]> wrote:
>=20
> I've (at last) attempted to write a developer-friendly narrative =
explanation of all of this stuff here.  How CORS works, the permission =
model, and some of the historical reasoning behind the various choices.
>=20
> =
https://docs.google.com/document/d/1AtxTDw-g9BSRW9n9kGTTqNkDTGcVfSKPAOjVGk=
PFu2k/edit?usp=3Dsharing
>=20
> Yes, it's a Google doc for now since that was fastest for me to =
compose, but if people think it is useful, I can incorporate comments =
and maybe we can turn it into a WebAppSec WG note or joint TAG finding.
>=20
> -Brad
>=20
>=20
>=20
> On 4/1/16, 11:26 AM, "Tim Berners-Lee" <[email protected]> wrote:
>=20
>> Thank you Jonas, for that clarification.
>> some response inline.
>>=20
>>> On 2016-01 -21, at 01:24, Jonas Sicking <[email protected]> wrote:
>>>=20
>>> On Mon, Jan 18, 2016 at 3:27 PM, Mark Nottingham <[email protected]> =
wrote:
>>>> ... or at least the motivations behind the decisions explained. =
It's pretty impenetrable now, and even security folks don't profess to =
know all of the details behind CORS any more.
>>>=20
>>> I'm bummed to hear that aspects of CORS is still confusing even to =
the
>>> TAG. This stuff likely needs to get documented someplace. I had =
hoped
>>> that it'd get documented in the spec, but maybe there's a better
>>> place?
>>=20
>> Perhaps the problems are that it is complicated, rather arbitrary, =
and not derived from general principles..
>>=20
>>>=20
>>> I'm not actually sure what exact confusion is being discussed in =
this
>>> thread is, so I'll address some of the questions I most commonly =
get.
>>>=20
>>> Q: What does the withCredentials flag do.
>>> A: When it's set to false, requests are sent containing only the
>>> information provided by the requesting website. I.e. the requesting
>>> website's provided URL, headers and request body. The only =
information
>>> that's added by the browser is information that's hardcoded into the
>>> browser and does not depend on user information. So for example the
>>> user-agent header. No cookies, authentication headers, or =
client-side
>>> certificates are added by the browser to the request before it is =
sent
>>> to the target website.
>>>=20
>>> However setting withCredentials to false does not prevent the
>>> requesting website from adding credentials through cookie headers,
>>> authentication headers, URL parameters or any other way that's =
exposed
>>> through the API which triggered the request.
>>>=20
>>> Additionally, the response data that would normally affect the =
client
>>> data storage is ignored. So for example set-cookie response headers
>>> are not written to the browsers cookie storage. The returned =
response
>>> is also not stored in the normal http cache, though if appropriate
>>> browsers may store it in a specific
>>> "CORS-requests-with-withCredentials-set-to-false" cache.
>>>=20
>>> When withCredentials is set to true, requests are handled like
>>> "normal" requests do in a browser. That means that cookies from the
>>> users cookie storage are added based on the target URL. Cached
>>> authentication data is added through the authentication header.
>>>=20
>>> The response is likewise processed like normal, so set-cookie =
headers
>>> are processed and the response is cached, if appropriate, in the
>>> normal browser http cache.
>>>=20
>>> 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.
>>>=20
>>> Sadly there is no, to me, known mechanism for detecting if a given
>>> server is behind a firewall.
>>=20
>> That=E2=80=99s 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=E2=80=A6 then you are =
behind a firewall =E2=80=A6 =20
>> 3) BUT that isn=E2=80=99t 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.=20
>>=20
>> 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.
>>=20
>>> Q: Is it safe to always set "Access-control-allow-origin: *" on all
>>> responses from a server.
>>> A: As long as the server is connected to the public internet, yes it
>>> is. It does not leak any information that couldn't be loaded using
>>> curl or any other non-browser HTTP client.
>>=20
>>>=20
>>> If the server is behind a firewall and might contain sensitive
>>> information, the header should not be added.
>>=20
>> Well, the header should be added for any public resource.
>> Some servers in fact handle the access control for the different =
resources on the site, and so in that case they ought to use that =
function to drive the headers automatically.  THAT is what should be =
coded up in the common servers.
>> That would help the server manager do the right thing.
>>=20
>>=20
>>>=20
>>> Q: Why does CORS not allow "Access-control-allow-origin: *" together
>>> with withCredentials=3Dtrue?
>>> A: It was felt that this was too big of a foot gun.
>>>=20
>>> 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=3Dtrue.
>>>=20
>>> 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.
>>>=20
>>> 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.
>>>=20
>>> 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.
>>=20
>> Any arguments about making things easy or difficult for server admins =
to=20
>> shoot themselves in the foot coming from a non-optimal attitude.
>> To first order, the system must implement a security protocol which =
allows
>> people to do the right thing =E2=80=94 to give the right access to =
the right resources
>> by the right people and origins.  Yes, by all means make the server
>>=20
>> Q: Why was reflecting the incoming origin in the header the thing =
which was picked
>> as the ay of saying =E2=80=9Cyes this really is public=E2=80=9D?  Why =
not =E2=80=9Caccess-control-allow-origin **=E2=80=9D or something
>> It is a pain to code, needs two or three lines of not-newbie-obvious =
..htaccess in Apache, etc.=20
>> Result? the recipe is sent around
>> and new server code does it by default for everything.
>>=20
>> 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.
>>=20
>>=20
>>=20
>>> 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: *=E2=80=9D.
>>=20
>> Well no, not if they only want 7 specific domains to have access.
>>=20
>>> Keep in mind that static
>>> responses can generally be read from non-browser HTTP clients like
>>> curl anyway.
>>>=20
>>> 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.
>>>=20
>>> 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.
>>=20
>> There are lots. They may be turned on by default.  A concern is they =
tend to just defeat CORS=20
>> and they don=E2=80=99t necessarily distinguish between public =
resources and others.
>>=20
>> Also people use CORS proxies to access the web, which are associated
>>=20
>>=20
>>> [...]
>>>=20
>>>=20
>>> If I'm not addressing the concern/questions from the TAG then please
>>> let me know.
>>=20
>> I think the top two issues the TAG had is
>>=20
>> 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.
>>=20
>> 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.    =
A good=20
>>=20
>> c) Asking server writers to do the origin reflection thing is =
unreasonable
>>=20
>>=20
>>>=20
>>> I'd really love it if this type of information could make it into =
the
>>> spec in a way that is understandable to more people.
>>>=20
>>> / Jonas
>>>=20
>>=20
>>=20