Draft CORS guidance for an IVOA JSON protocol

Russ Allbery eagle at eyrie.org
Mon May 27 18:27:49 CEST 2024


Markus Demleitner via grid <grid at ivoa.net> writes:
> On Thu, May 23, 2024 at 12:18:10PM -0700, Russ Allbery via grid wrote:

>> 1. The service is unauthenticated.  CSRF concerns do not apply and you
>>    should use an open CORS policy.  To do this, register an OPTIONS
>>    handler for every API route (usually one catch-all OPTIONS handler is
>>    sufficient if you don't have different policies per route) that
>>    responds with a 204 code and the following headers:
>>
>>        Access-Control-Allow-Origin: *
>>        Access-Control-Allow-Methods: GET, POST, OPTIONS
>>
>>    You may also want to send Access-Control-Allow-Headers if your web
>>    service accepts non-simple-request headers, and
>>    Access-Control-Expose-Headers if your service returns extra headers
>>    that should be readable by JavaScript.

BTW, I wasn't sure whether this was obvious, but the above work *only* has
to be done on the server side.  The client side doesn't need to do
anything at all.

This is true in general for all CORS scenarios: all of the work is on the
server.  Browsers will send the pre-flight check because that's part of
the normal operation of a browser.  Non-browser clients will not send a
pre-flight check and *should not* send a pre-flight check, since they are
not affected by the security issues that CORS is defending against.

All of this CSRF stuff exists only because browsers are confused deputies
[1] by design: they are essentially sandbox environments in which you run
arbitrary untrusted code from the Internet.  CORS and other CSRF
protection mechanisms are about enforcing the sandbox.  Without the worry
about running untrusted code, CORS can be ignored.

[1] https://en.wikipedia.org/wiki/Confused_deputy_problem

One of the reasons why CORS is nicer than the pre-CORS CSRF mitigation
strategies required by simple requests like x-www-form-urlencoded POST is
that the latter, in order to protect against browsers, sometimes have to
do things that non-browser clients *do* need to know about and have to
navigate.  If one uses a web service protocol that forces CORS pre-flight
checks from browsers, this has the huge advantage that non-browser clients
can completely ignore it and all the work is only on the server.

> Now, I'd say we can use securityMethod to indicate "this is a service
> for which CSRF may be an issue"; basically, we'd have to come up with a
> pattern for "auth *may* be in use on this interface" (as opposed to
> "*is* in use in this interface", which is the current interpretation.
> This sounds very doable, and I'm happy to collaborate with anyone trying
> to do that, both regarding VOResource and RegTAP changes, which I think
> I could prototype at a moment's notice.

I agree with having a mechanism to tag interfaces as possibly
authenticated.  In a world where I suspect more compute will move closer
to the data, my guess is that there will be an increasing number of
archives that allow inexpensive operations without authentication but
require authentication for expensive operations.

When it comes to CSRF protection, though, I think registry support would
only be needed for hypothetical x-www-form-urlencoded POST network
encoding where there may be CSRF protection mechanisms that the client has
to be aware of.

For a JSON-based protocol using CORS, since all the work is on the server,
I think the only registry involvement would be (a) potentially registering
portals that may make browser-side remote calls to other archives and that
archives may therefore want to whitelist for CORS in case 3c, and (b)
defining how to register such portals for a given site if we go down the
case 3d route (which I would only do if it turns out there's enough
interest, since it's a fair bit of work).

Therefore, I think the ward_off_csrf column wouldn't be relevant for a
JSON-based protocol, only for an x-www-form-urlencoded POST protocol with
standardized CSRF protection mechanisms.

The possibly-authenticated part, though, is a really good idea because
portals will need to know whether they may need to send credentials to get
full API access.  Although hopefully at least some of that will be obvious
when they get a 401 response to an attempt to use some API.

> * and 'In-Browser clients MUST perform pre-flight checks and do
>   <whatever> when rr.interface.ward_off_csrf is 1.  They MUST NOT
>   expect other intervaces to implement CSRF mitigation measures.

I don't think we need to say this, and in fact I don't think it's a good
idea to say this because it implies that someone implementing an astronomy
protocol has to do something about this on the client side.  But this
isn't something under ouar control.  All browsers simply *will* do this
pre-flight check whether we want them to or not because it's part of the
definition of the browser security model.  If a browser didn't do this for
untrusted JavaScript, it would have a major security vulnerability.  And
if the browser did have some mechanism to determine whether certain
JavaScript is completely trusted, then it would be correct to not do
pre-flight checks because, in that case, it's not a confused deputy and is
equivalent to a non-browser client.

-- 
Russ Allbery (eagle at eyrie.org)             <https://www.eyrie.org/~eagle/>


More information about the grid mailing list