4

I'd like to understand this a bit better. The mental model I'm operating with at the moment works something like this:

  1. JS hosted at foo.com wishes to access a resource hosted at bar.com. That's not the sort of thing that browsers like to expose their users to, unless it can be shown that bar.com welcomes this request.
  2. So the foo.com JS essentially breaks the request into two halves. First we send a dataless request of the proper kind (GET, POST, etc) via the XMLHttpRequest object. The server at bar.com returns what it would ordinarily respond to basically any request, which might or might not include an Access-Control-Allow-Origin header. (EDIT: This was a misconception - see excellent comment by apsillers below)
  3. If the browser does get such a header, it scans it for the Origin (in this case foo.com). If present, it proceeds to send off the actual request that it was asked to send. If not, it refuses. (EDIT: This was also not quite right)

If this model is correct, I'm confused as to why the browser sends out an Origin header with this preliminary request. Doesn't the checking-for-a-match happen client side? What does sending out this header achieve?

Greg Pallis
  • 227
  • 1
  • 10
  • 1
    Actually, a dataless preflight request only happens with "non-simple" HTTP verbs *other than* GET and POST (e.g., PUT, DELETE, etc.), and the preflight request uses the OPTIONS verb. – apsillers Nov 19 '12 at 18:36
  • 1
    @apsillers -- other verb *or* the use of a custom header. I don't know why; I assume this patches some security hole. – Malvolio Nov 19 '12 at 18:38
  • @Malvolio Right, thanks, I forgot about customer headers. The non-simple verbs make more sense to me (since we don't want a DELETE hitting the server unless the server says it is welcome). I too am mystified about the custom header preflight requirement. – apsillers Nov 19 '12 at 18:41
  • @apsillers, can I make absolutely sure I'm getting your clarification correct? I'm understanding you as saying that such 'preflight' requests are not used to verify GET and POST verbiage, only verbs such as PUT, DELETE, etc? (unless there are custom headers) If so, how are things enforced for GET and POST? – Greg Pallis Nov 19 '12 at 19:00
  • 1
    That is correct. In CORS terms, GET and POST are called "simple" HTTP verbs, and they are allowed to reach the cross-origin server (but the browser may decide after the HTTP request is complete that JS doesn't get to see the result). The `Origin` header could be useful here, since any origin can successfully *send* a GET/POST request to any other origin, but the response might not be visible to JavaScript if the browser blocks it. (Requests other than GET and POST are *not* allowed to reach the sever until after a successful OPTIONS preflight, which you already understand.) – apsillers Nov 19 '12 at 19:16
  • In sum, a CORS-aware browser always issues GET/POST requests regardless of origin, but it may deny JavaScript access to the response data in accordance with the same-origin policy. You may find [this previous answer of mine](http://stackoverflow.com/questions/13400594/understanding-xmlhttprequest-over-cors-responsetext/13400954#13400954) helpful also. – apsillers Nov 19 '12 at 19:21
  • @apsillers - thank you! With your help, and that of epascarello, I've definitely levelled up my understanding a great deal. I'm still a tiny bit unclear on one detail - why Chrome would send out the Origin header with a GET request? That seems a little inefficient to me; I'm now sure that no servers do anything with this information (as it's GET, not OPTIONS), and presumably Chrome has access to the Origin anyway when the response arrives. But perhaps Chrome does not have access to this information in any convenient way, and this is a matter of administrative convenience. – Greg Pallis Nov 19 '12 at 23:03
  • Aha! It's a CRSF thing. Right, I think I understand this fully now. Thank you so much! – Greg Pallis Nov 19 '12 at 23:15

1 Answers1

3

It is how CORS works. It is basically a handshake that says yes you are welcome to talk with me. You can not know if it is possible unless the 3rd party is contacted.

The following is a partial portion of the Preflighted_requests section of the MDN article:

Unlike simple requests (discussed above), "preflighted" requests first send an HTTP OPTIONS request header to the resource on the other domain, in order to determine whether the actual request is safe to send. Cross-site requests are preflighted like this since they may have implications to user data. In particular, a request is preflighted if:

It uses methods other than GET or POST. Also, if POST is used to send request data with a Content-Type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, e.g. if the POST request sends an XML payload to the server using application/xml or text/xml, then the request is preflighted. It sets custom headers in the request (e.g. the request uses a header such as X-PINGOTHER)

epascarello
  • 185,306
  • 18
  • 175
  • 214