Hi All,
As I brought up in the call wednesday I have some ideas for simplifying
the spec a bit.
I think the syntax for the access-control header has gotten a little bit
too complicated. There are two things that I think can be removed; the
deny rule and the methods lists. Here's how:
=== The method lists ===
The method list is only useful for the OPTIONS request. This request is
basically there in order to make sure that the server is aware of the
existence of the AC spec, and that it is prepared to receive unsafe
cross-site requests. But saying that you are prepared to receive
requests is not the same as a promise to act on them. A server could
simply state that it accepts any requests from any server, as long as it
does the appropriate security checks once the actual request comes in.
In fact, it's even recommended that the actual security checks be done
in response to the request since otherwise there is a risk that a cached
OPTIONS check will still allow requests to be sent for some time if
security policies are ever changed (though never longer than the time
specified in the Method-Check-Max-Age header of course).
Additionally, the current syntax is inconsistent. When doing an OPTIONS
request we send the requesting server's uri in the Referer-Root header.
The reply (simplified) contains a set of uris. The set of uris is only
used to check if the requesting site is part of the set, the rest of the
set is ignored. This allows the server to do server side filtering and
reply with "allow <*>". This does not mean that any other server is
allowed to perform unsafe requests without doing an OPTIONS request
first. In other words, we assume that sending a different Referer-Root
could yield a completely different set of allow rules.
This is not true for the set of methods. Here we do include the method
in a Method-Check header, but we do remember the full set of methods
that is included in the reply. I.e. we assume that sending a different
Method-Check header would always yield exactly the same allow-rules.
I propose that we remove both the Method-Check header, and the list of
methods from the Access-Control header. This has several advantages:
* It forces the security checks to happen at the time of the actual
request which is what we should encourage anyway.
* It makes the syntax a lot simpler and easy to understand.
* It removes the inconsistencies.
* It makes the implementation simpler.
* And it means that sharing the Access-Control header for GET requests
and OPTIONS requests makes more sense.
This does assume that there is no methods that are so harmful that the
server could not deal with cross-site requests of this type at all. I.e.
they would cause harm before reaching the server side script. The spec
would only allow all methods (reply with a set of allowed uris that
includes the requesting one) or no methods at all (don't reply anything,
or don't include the requesting uri in the set of allowed ones). I don't
know of any such methods though.
If that really is the case I would suggest we still don't include the
Method-Check header, but instead add a separate response header that
lists the set of allowed headers. However this would remove the first
bullet in the list above which would be a pity.
=== The deny rule ===
Originally I think the deny rule came from me (not sure if this is true,
not trying to take undue credit, rather trying to take the blame ;) ),
and I think I had two reasons for this:
1. A way to allow server operators to quickly stop all cross-site
requests without having to take down the whole site.
2. You would be able to put a sensitive resource on a server even if the
server sent a allow<*> rule to all responses. You'd simply stick a
<?access-control deny="*"?> PI in the resource.
But I think there are better solutions to these problems.
Thomas Roessler pointed out that 1 is better solved by simply stopping
all requests that included a Referer-Root header. This could be done on
a server level and would also stop any cached OPTIONS requests from
making unsafe actions reach a CGI script.
I like this idea a lot. The only problem is that I'm worried that the
Referer-Root header might get picked up by other specs due to its
usefulness and generic name. However if we specified that Referer-Root
should only ever be included in cross-site request, then that should
mitigate that problem. In fact, i've wanted to add a header for
cross-site image and script loads to allow the server to reject these
more easily. (That would of course not be part of this spec).
I'm not really sure 2 is needed, nor would be used very often. You could
simply not place the resource on the server if you know that it's
sending allow<*> rules. And if you don't know that you are unlikely to
put the PI in the resource at all.
The main benefit of doing this is simplicity of the spec. However there
is actually one more benefit. It would mean that making cross-site HEAD
requests would be as safe as cross-site GET requests. The reason they
aren't currently is that the response could include an allow <*> rule
could include a deny-rule in a <?access-control?> PI. A HEAD request
would only see the allow<*> header, but not the deny rule in the PI.
This wouldn't really be a problem if there was no deny rules. It would
mean that a resource that could be accessible using a GET request might
not be accessible using a HEAD request though, but I think that is ok.
And it's a lot better than a content author accidentally allowing HEAD
requests to resources that could include access-control PIs if
deny-rules exist. Something that I think could very well happen.
/ Jonas