Reputation: 64433
According to samples from here:
If a request uses methods other than GET, HEAD 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.
So in the following example, the pre-flight is carried out because of the XML Content-Type and the custom header X-PINGOTHER
:
var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/post-here/';
var body = '<?xml version="1.0"?><person><name>Arun</name></person>';
function callOtherDomain(){
if(invocation)
{
invocation.open('POST', url, true);
invocation.setRequestHeader('X-PINGOTHER', 'pingpong'); //<====
invocation.setRequestHeader('Content-Type', 'application/xml'); //<====
invocation.onreadystatechange = handler;
invocation.send(body);
}
}
But in the so-called pre-flight OPTIONS request (below), the server is only notified of the HTTP method and custom header. No one told the server about the XML Content-Type
.
Logically, as long as the preflight request is sent, it implies the Content-Type is not in the 3 forms which need no preflight. But there can be numerous other possibilities. The bottom line is, server should be able to know why the preflight request is sent.
So how could server reasonably decide whether to allow this request with a missing piece of puzzle (the content-type)?
Upvotes: 1
Views: 835
Reputation: 112917
CORS is almost always safe. Quoting from the Fetch Standard,
For resources where data is protected through IP authentication or a firewall (unfortunately relatively common still), using the CORS protocol is unsafe. (This is the reason why the CORS protocol had to be invented.)
However, otherwise using the following header is safe:
Access-Control-Allow-Origin: *
Even if a resource exposes additional information based on cookie or HTTP authentication, using the above header will not reveal it. It will share the resource with APIs such as XMLHttpRequest, much like it is already shared with curl and wget.
Thus in other words, if a resource cannot be accessed from a random device connected to the web using curl and wget the aforementioned header is not to be included. If it can be accessed however, it is perfectly fine to do so.
Thus, a server does not need to know anything about the content type of the request to know how to respond to the OPTIONS request. The server just needs to know: is the URL being asked about only accessible via IP-based authentication, or behind some firewall or intranet? If it is, then it should deny the OPTIONS request. If it is not, i.e. if the resource is accessible via the public internet using tools like curl, wget, telnet, or your favorite HTTP library, then it should allow the OPTIONS request. Doing so will just give browsers the same access as those other tools.
The server can then make further decisions when the subsequent POST request comes in. For example, maybe the server wants to reject POSTs with the wrong Content-Type. But it would always want to do this. It wouldn't want to only reject the OPTIONS request from CORS-respecting browsers; instead it should reject the POST request, from any source.
(The reason why browsers are special is the following. Consider an intranet that follows bad security practices and is readable by anyone with their IP address in a certain range, i.e. anyone using a company computer. Normally, that is no problem: people inside the company who use curl can access the data, and people outside it who use curl cannot. However, consider someone inside the company that browses to some malicious website, https://evil.com/. If evil.com uses the XHR API to access http://intranet/secret-data, then the request will come from a privileged IP address, since it's the browser on the privileged user's computer doing the request. To prevent these kind of security leaks, the CORS protocol was invented, so that instead of doing a direct POST to http://intranet/secret-data, the browser first does an OPTIONS request, for which the whole of http://intranet will probably just say "no you can't access this", and then the POST never happens.)
Upvotes: 3