Re: Simplifying the AC spec

The deny rule originated in the Voice Browser work.  The primary use case was the desire to enable simple blacklisting when allow "*" was specified.  The requirement for having this supported in the PI and enforced by the user-agent was the requirement to allow document author control over access while not assuming that the document author had control of the website configuration.  Without it you either have universal access or white-list-based access.

The rules about deny in headers overriding PIs and things came later as the VBWG work did not use HTTP headers at all.

That said, deny= clearly makes the algorithm a fair bit more complicated semantically, more prone to implementation error, and more prone to developer confusion.  

--Brad

Jonas Sicking <jonas@sicking.cc> wrote: 
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 
 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  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

Received on Friday, 8 February 2008 22:02:40 UTC