28

I'm a bit confused about the security aspects of CORS POST requests. I know there is a lost of information about this topic online, but I couldn't find a definite answer to my questions.

If I understood it correctly, the goal of the same-origin policy is to prevent CSRF attacks and the goal of CORS is to enable resource sharing if (and only if) the server agrees to share its data with applications hosted on other sites (origins).

HTTP specifies that POST requests are not 'safe', i.e. they might change the state of the server, e.g. by adding a new comment. When initiating a CORS request with the HTTP method POST, the browser only performs a 'safe' preflight request if the content-type of the request is non-standard (or if there are non-standard http headers). So POST requests with standard content-type and standard headers are executed and might have negative side effects on the server (although the response might not be accessible to the requesting script.)

There is this technique of adding a random token to every form, which the server then requires to be part of every non-'safe' request. If a script tries to forge a request, it either

  1. does not have the random token and the server declines the request, or
  2. it tries to access the form where the random token is defined. This response with the random token should have the appropriate head fields, such that the browser does not grant the evil script access to this response. Also in this case the attempt fails.

My conclusion is that the only protection against forged POST requests with standard content-type and headers is the technique described above (or a similar one). For any other non-'safe' request such as PUT or DELETE, or a POST with json-content, it is not necesssay to use the technique because CORS performs a 'safe' OPTIONS request.

Why did the authors of CORS exclude these POST exempt from preflight requests and therefore made it necessary to employ the technique described above?

sideshowbarker
  • 62,215
  • 21
  • 143
  • 153
sauerburger
  • 2,843
  • 3
  • 21
  • 33

1 Answers1

41

See CORS - What is the motivation behind introducing preflight requests? & other answers there.

The reason CORS doesn’t require browsers to do a preflight for application/x-www-form-urlencoded, multipart/form-data, or text/plain content types is that if it did, that’d make CORS more restrictive than what browsers have already always allowed (and it’s not the intent of CORS to put new restrictions on what was already possible without CORS).

That is, with CORS, POST requests that you could do previously cross-origin are not preflighted—because browsers already allowed them before CORS existed, and servers knew about them. So CORS changes nothing about those “old” types of requests.

But prior to CORS, browsers wouldn’t allow you to do a cross-origin application/json POST at all, and so servers could assume they wouldn’t receive them. That’s why a CORS preflight is required for those types of “new” requests and not for the “old” ones—to give a heads-up to the server that this is a different “new” type of request that they must explicitly opt-in to supporting.

sideshowbarker
  • 62,215
  • 21
  • 143
  • 153
  • 9
    Indeed, we allowed POST because `
    ` already did and there was no way we were going to be able to restrict `
    `.
    – Anne Sep 28 '16 at 06:33
  • In other words, the old content-types are allowed so as to not break already built web applications for which browsers were allowing the old content-types. So, intention is have backward compatibility with browsers behaviour. If policy adds more restrictions to browsers, web apps will start failing. – Shailesh Pratapwar Nov 07 '19 at 06:34