Search code examples
resthttpcorshttp-method

Is my server expected to return a 200 for an HTTP OPTIONS methods when the connection point is forbidden to the current user?


Reading various documentations (such as the w3c CORS), I have to say that the OPTIONS does not seem that well documented at all.

I'm wondering whether my REST server is doing it right, which is returning a 403 if the client tries to access a connection point which is forbidden (whether it exists or not does not even always matter, although at times the server may return 404 instead.)

The OPTIONS documentation, though, does not seem to infer that such a return code is valid.

I've found this stackoverflow Q/A where the accepted answer seems to say that we can return any error code.

I would imagine that it would be a security hole to allow the OPTIONS to passthrough when the user is not allowed. At the same time, the OPTIONS defines the Access-Control-Allow-Credentials header and I don't see how I could ever make that header useful if I return a 403 on such connection points. (In other words, to me that sounds contradictory.)


Solution

  • Short answer: If you do actually want the OPTIONS response to be useful as far as CORS-enabling the server, then you shouldn’t return 403 just because the user isn’t logged in.

    Details:

    It’s never invalid for a server to return a 403 for an OPTIONS request. The CORS protocol doesn’t require your server to return a 2xx success response for an OPTIONS request. But if your server doesn’t return a 2xx for OPTIONS requests to a particular URL, then CORS preflight OPTIONS requests to that URL will fail. So if that’s what you actually want to happen, then responding with a 403 is fine — so is responding with a 405 or a 501 or whatever other response code might have a meaning appropriate to your particular case.

    But it’s important to keep in mind that the CORS protocol requires browsers to never send authentication credentials as part of the CORS preflight OPTIONS request. So if your server is configured to require authentication in order for OPTIONS requests to produce 2xx success responses, then all CORS preflights coming from browsers are going to fail 100% of the time. In other words, you’d be ensuring that all requests will fail that are coming to the server from frontend JavaScript code running in a browser and that add custom response headers (e.g., Content-Type or Authorization headers) and so that trigger preflights.

    I’m not aware of any specific security hole that could occur by responding with 2xx to unauthenticated OPTIONS requests (from users who are not allowed). That doesn’t permit users to get any info from your server beyond whatever you intentionally choose to put into the response headers you send in response to the OPTIONS request. And of course it doesn’t prevent you from requiring authentication for GET or POST or whatever other methods. But in terms of the CORS protocol, it’s the only way for your server to indicate what methods and request headers it allows in requests from frontend JavaScript.


    Note also: the current actively-maintained requirements for CORS are defined in the Fetch spec https://fetch.spec.whatwg.org. The https://w3.org/TR/cors spec is obsolete and no longer maintained and shouldn’t be used for anything (see https://w3.org/2017/08/16-webappsec-minutes.html#item03 and the answer at https://stackoverflow.com/a/45926657/441757).

    I don’t know why the https://w3.org/TR/cors spec isn’t already been clearly marked obsolete, but I’ll try to make sure it gets marked as such soon.