Thomas Roessler wrote:
On 2008-06-10 16:41:41 -0700, Jonas Sicking wrote:
Getting access to a users cookie information is no small task.
I disagree. There are any numbers of real-world scenarios in which
cookies are regularly leaked - JavaScript that's loaded from
untrusted sources, and captive portals are just two examples which
make people bleed cookies. Basing the design here on the premise
that cookie-based authentication should somehow be enough to protect
against cross-site request forgery strikes me as unwise, in
particular when the cost is in additional complexity (and therefore
risk).
Well, if you can get access to a users cookies and auth information then
nothing that we do here matters at all. Or at least matters to a much much
smaller extent. This whole spec is basically here precisely to protect the
information that is protected by cookies and auth headers (and for most
sites only cookies).
Ooops, I let your remark about "getting access to a users cookie
information" above lead me on a bogus path of argument. That's what
I get for doing e-mail on a train. :-)
The fundamental point is that (a) GET request and (b) some POST
requests can be made with the user's cookies. As far as web
application development is concerned, it's probably a really good
idea to consider the cross-site request horse (as opposed to the
cross-site information access horse) to have left the barn (even if
it hasn't left the barn totally).
Now, the working group evidently doesn't want to make that
assumption for generic POST requests (which is fine); that's why we
have the pre-flight check. That's fine with me.
However, we're now getting to a point at which we try to prevent the
occurence of certain cross-site requests, specifically with cookies.
The cost here is complexity in the protocol design and
implementation (which is complexity to the deployer).
Hmm.. I'm confused. All requests we are trying to prevent are ones with
cookies. First you say that you are ok with the pre-flight
request, but then you say that you don't want to prevent certain
cross-site requests. Isn't that the whole point of the pre-flight.
Or are you saying that you're ok with
The benefit is questionable at best, in particular if you consider
POST: There are some POST requests that, under the proposed model,
couldn't be made using XMLHttpRequest, but could be made using
form.submit(). Do you really expect anybody to still understand
that?
It is certainly not ideal, but it's better than any alternative I think.
Also note that this is already the case with the spec as is, without my
newly proposed additions.
With the spec as is it is already not possible to do cross-site POSTs
with content-type text/plain using XHR without opt-in, while it is
possible using <form>.
The only solutions to this that I can think of are these:
1. Leave things as is and accept that Access-Control prevents certain
requests (without opt-in) that <form> already allows.
2. Modify Access-Control such that it allows exactly those requests that
are currently possible using <form> without opt-in. Anything that
is not possible using <form> would require opt-in.
3. Modify Access-Control such that it allows a superset of what is
possible using <form>.
It seems to me like 2 would add a lot of complexity to the spec, we
would have to write rules saying that only when the content type is
"text/plain" or "multipart/form-data" then allow. This seems really
messy to me and it also makes it even harder to stricten up <form> in
the future (something that would *greatly* help CSRF prevention).
Option 3 scares me a lot. For example SOAP servers have been brought up
in the past that currently might only be protected by the content type
never being "text/xml" from <form>. I have also heard of sites that
implement CSRF protection today by submitting their forms using XHR and
setting a custom header. They thereby rely on the fact that you can't
cross-site POST today while setting custom headers.
So while I agree 1 is non-ideal, it seems like the least bad option. I'm
not that worried that people will simply forget about the current
security model of the web, just because we publish the Access-Control spec.
When seeing questionable benefits on the one hand, and an
increasingly messy and incomprehensible design on the other, then
I'd rather see us not make this case.
I was getting at the fact that the recent change proposals are
moving away from scenarios in which the web application author
writes a policy in a simple language, and get more and more into a
scenario in which this policy is broken into pieces that are spread
across multiple headers.
I think the sane options are either an extension to the policy
language (so that there is one model to look up), e.g.:
allow method post with cookies with http-auth oauth from w3.org \
except people.w3.org
I'm less concerned about what exact syntax we use than what features we are
providing. As long as it is easy to understand.
I agree on that; the syntax that I put in up there is probably not
even consistent with what's in the draft. It was meant as an
example only.
That said, I do want to avoid the situation we had before where
you had to specify in far too great detail your policy, such as
for each allowed site separately list the allowed methods for
that site.
Well, *that*, for one, isn't a syntactic question, as it implies
that certain policies couldn't be implementable without having to
use server-based techniques (enabled thanks to the origin header).
Yes, I do think that people would be able to do server-side enforcement
of the headers they only want to allow for some 3rd party sites. My
concern is headers that they aren't even thinking of exist, or ones that
are added support for after they deploy Access-Control support.
However I still don't see an important distinction between the header
you proposed above and the one I proposed. So if your proposal
alleviates peoples concern about complexity then I am fine with that.
Other than that I don't think it matters much, it's just a syntactic
question.
... or a model where we do away with the notion of a policy language
entirely, and rely on the Access-Control-Origin (or whatever it's
called this week) and the server making a decision as our main
mechanism. This goes back to Mark Nottingham's ideas from January,
when he suggested that using HTTP Vary headers and Referer-Root was
indeed enough.
For an unsafe method, the server indicates that it's prepared to
deal with cross-site requests during the pre-flight phase, and then
makes its real decision at the time of the request, based on that
request's Access-Control-Origin.
This is still relying on that the server is able to deal with the unsafe
request. I.e. the server is still forced to opt in to nothing, or opt in to
all possible combinations of http methods and headers.
Yes, that assumption is in there.
Which is exactly what my proposal was trying to prevent. That was the
whole point of it. If we don't archive that then my concerns have not
been alleviated.
So it seems no different from what the spec says today in that regard.
The difference is that we throw out the idea of having a complex
policy engine of any sort in the client.
How is that different from what we have today in the spec?
For safe methods, the server can just use HTTP error codes.
While this is indeed a differnt model, it seems to be the one that a
lot of the discussion here is edging toward -- e.g., the defenses
against decoupling the preflight check from the "real" request all
rely on server-side enforcement of the policy.
What I'd really like to see us avoid is a scenario in which we're
creating a mess by mixing the various models to the extent that the
entire model becomes incomprehensible.
I don't think the model is especially complicated for the server
administrator, even with the separate headers. It seems to me that the
number of headers is a poor measurement of the complexity of the spec.
I'm not even claiming that the number of headers is a measurement of
the complexity of the spec. What I am, however, saying is that
having some things configurable per server, and others globally, is
a recipe for confusion (in particular to people who don't need to
touch their policies daily), and that a simpler model is preferable
over that.
With my proposal you can still rely on the client to enforce different
policies per server if you so wish. You can simply send different header
values depending on what the (Access-Control-)Origin says. But you are
not forced to as with the previous spec.
Or you can simply always opt in to all the headers that you expect to
deal with from any server, and then use server-side logic to enforce
more complex policies if you so wish.
The smaller portions a server opts in to, the smaller the risk
that they accidentally opts in to something where they
accidentally shoot themselves in the foot.
While I sympathize with that notion, I think that the current
approach (mixing a policy language with headers that possibly need
to be set differently for different sites) is likely to mess up
things further and make analysis harder.
I do think that we server site authors best by making things simple,
easy and consistent. That isn't the case with the model getting
ever more baroque. Sorry.
I guess it depends on what you define as "simple". I think of it as the
fewer things you have to keep track of the simpler it is. I think having to
keep track of the full set of http features for the server is more than
making sure to get one or two extra headers right.
If you look at information flows (and at your own arguments in
another branch of this very thread), then the current model indeed
requires you to deal with all kind of weird behavior, since the
ability of a script to exercise possibly arcane and unspecified
levers that might control what an HTTP response looks like will
translate into the ability of that script to perform cross-site
requests. The more different headers and different code paths are
involved with that, the higher the risk that things actually go wrong.
Agreed. Though I assume that by "arcane and unspecified levers" you mean
things like random http headers and http methods. Including ones that
are totally unrelated to this spec.
A model that (a) simplifies the language, and (b) minimizes the code
paths that can be used to control the server's behavior would seem
the more sane one, and would seem to be the one that's easier to
control for server administrators, e.g. from filters that they can
put in front of their web application.
Agreed. But to archive (b) I do think we need my proposal since
otherwise as soon as someone opts in a 3rd party server can hit all the
code paths executed by all possible headers and methods.
/ Jonas