George Mauer George Mauer - 3 months ago 8
Ajax Question

Why does the browser allow xorigin POST but not PUT?

Consider the very simple example of using

XMLHttpRequest
.

The following posts properly ( you can see it in the network tab or by directing your browser to
http://requestb.in/yckncpyc
) although it prints a warning to the console


XMLHttpRequest cannot load http://requestb.in/yckncpyc. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'null' is therefore not allowed access.




const method = "POST"
const req = new XMLHttpRequest()
req.open(method, 'http://requestb.in/yckncpyc')
req.send("foobar")
console.log("sent")
req.addEventListener('load', function() { console.log(req.status, req.response) })





Sure. I get that. What I don't get is why merely changing the verb used to a
PUT
results in something completely different. The request sent is an
OPTIONS
preflight request and prints


XMLHttpRequest cannot load http://requestb.in/yckncpyc. Response to
preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'null' is therefore not allowed access.




const method = "PUT"
const req = new XMLHttpRequest()
req.open(method, 'http://requestb.in/yckncpyc')
req.send("foobar")
console.log("sent")
req.addEventListener('load', function() { console.log(req.status, req.response) })





Why does the browser* treat these differently? It seems like something that would be done for security but that really makes no sense since an attacker can always use a POST instead of a PUT.

So what is the logic here?


  • Tried this in Chrome 52, Safari 9.1.2


Answer

GET, HEAD, and POST requests (with a couple other restrictions) can be made cross-origin with no additional communication. The responses cannot be examined, but the requests are allowed.

Anything else requires a preflight request to check the headers from the target site to see whether the request would be allowed.

The reason for such a setup is that GET, HEAD, and POST were historically allowed from browsers as a natural part of HTML semantics. Tags for scripts and CSS and images do GET requests, and forms do POSTs. When the CORS stuff was introduced, therefore, those were allowed under the assumption that sites were no more vulnerable to simple requests like that in an XHR world then they were in the simpler non-XHR world.

So simple requests are allowed, and the browser looks at the response headers to decide whether the requesting code in the cross-origin page should be allowed to see the response content. For other requests, the browser first sends an OPTIONS request to check the CORS response headers. Only if that looks OK (that is, if the response headers contain the appropriate "yes that's OK" headers) will the XHR be allowed to proceed.

Comments