9

There are several topics about the problem with cross-domain AJAX. I've been looking at these and the conclusion seems to be this:

Apart from using somthing like JSONP, or a proxy sollution, you should not be able to do a basic jquery $.post() to another domain

My test code looks something like this (running on "http://myTestdomain.tld/path/file.html")

var myData = {datum1 : "datum", datum2: "datum"}
$.post("http://External-Ip:port", myData,function(return){alert(return);});

When I tried this (the reason I started looking), chrome-console told me:

XMLHttpRequest cannot load http://External-IP:port/page.php. Origin http://myTestdomain.tld is not allowed by Access-Control-Allow-Origin.

Now this is, as far as I can tell, expected. I should not be able to do this. The problem is that the POST actually DOES come trough. I've got a simple script running that saves the $_POST to a file, and it is clear the post gets trough. Any real data I return is not delivered to my calling script, which again seems expected because of the Access-control issue. But the fact that the post actually arrived at the server got me confused.

  • Is it correct that I assume that above code running on "myTestdomain" should not be able to do a simple $.post() to the other domain (External-IP)?
  • Is it expected that the request would actually arrive at the external-ip's script, even though output is not received? or is this a bug. (I'm using Chrome 11.0.696.60 )
Nanne
  • 64,065
  • 16
  • 119
  • 163
  • This would mean it does protect against (some) XSS exploits, but not CSRF? Strikes me as weird anyways :P – markijbema May 09 '11 at 18:05
  • I retract my comment as per Michiels answer, it actually does make sense security-wise. – markijbema May 09 '11 at 18:07
  • you can try this [CHROME EXTENTION](https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?hl=en) – kplshrm7 Sep 19 '15 at 12:44

4 Answers4

5

I posted a ticket about this on the WebKit bugtracker earlier, since I thought it was weird behaviour and possibly a security risk.

Since security-related tickets aren't publicly viewable, I'll quote the reply from Justin Schuh here:

This is implemented exactly as required by the spec. For simple cross-origin requests http://www.w3.org/TR/cors/#simple-method> there is no pre-flight check; the request is made and the response cannot be read if the appropriate headers do not authorize the requesting origin. Functionally, this is no different than creating a form and using script to make an off-origin POST (which has always been possible).

So: you're allowed to do the POST since you could have done that anyway by embedding a form and triggering the submit button with javascript, but you can't see the result. Because you wouldn't be able to do that in the form scenario.

A solution would be to add a header to the script running on the target server, e.g.

<?php
header("Access-Control-Allow-Origin: http://your_source_domain");
....
?>

Haven't tested that, but according to the spec, that should work.

Firefox 3.6 seems to handle it differently, by first doing an OPTIONS to see whether or not it can do the actual POST. Firefox 4 does the same thing Chrome does, or at least it did in my quick experiment. More about that is on https://developer.mozilla.org/en/http_access_control

Marlies
  • 927
  • 1
  • 5
  • 18
  • So this would mean that while (as per Justin Schuh's answer) it seems logical that you should be able to do the post, there is no guarantee, as some browsers (Firefox in your example) actually don't let you do this. – Nanne May 09 '11 at 18:13
  • I tried earlier with FF 3.6 which didn't let me do it (it did the OPTIONS instead). Just now I tried with FF 4.0 which *did* allow the request (in the same way that Chrome/Safari do, without allowing you to see the result). – Marlies May 09 '11 at 18:17
  • @Nanne @Michiel The OPTIONS request you're seeing is because of preflighting - if you do a POST request with custom headers or a content-type set to something other than `application/x-www-form-urlencoded, multipart/form-data`, or `text/plain`, the browser attempts to make sure a request with those headers will be allowed by making an OPTIONS request before it makes the actual POST request. – no.good.at.coding May 10 '11 at 18:43
3

The important thing to note about the JavaScript same-origin policy restriction is that it is something built into modern browsers for security - it is not a limitation of the technology or something enforced by servers.

To answer your question, neither of these are bugs.

  • Requests are not stopped from reaching the server - this gives the server the option to allow these cross-domain requests by setting the appropriate headers1.

  • The response is also received back by the browser. Before the use of the access control headers 1, responses to cross-domain requests would be stopped dead in their tracks by a security conscious browser - the browser would receive the response but it would not hand it off to the script. With the access control headers, the server has the option of setting the appropriate headers indicating to a compliant browser that it would like to allow certain origin URLs to make cross domain requests.

    The exact behaviour on response might differ between browsers - I can't recall for sure now but I think Chrome calls the success callback function when using jQuery's ajax() but the response is empty. IIRC, Firefox will not invoke the success function.

Community
  • 1
  • 1
no.good.at.coding
  • 20,221
  • 2
  • 60
  • 51
  • Hmm, I'm confused. What would the use be to set the headers as "not allowed", but then still run the script? This means I can do my post (which is nice), although the same-origin policy prevents me from handling it like I would a same-domain request. Am I missing something? – Nanne May 09 '11 at 15:43
  • @Nanne Your JavaScript will be allowed to execute and make the request - the request will go through to the server but your JS may or may not receive the response. If the server sets the header allowing that domain (the origin) to make the cross-domain request, a newer browser which supports the access-control header will let the response through to your JS. If it's a browser that doesn't understand this mechanism of allowing CDR or if the server doesn't set the header allowing that origin, your JS will not get a response. Does that help clarify? – no.good.at.coding May 10 '11 at 18:37
0

I get the same thing happening for me. You are able to post across domains but are not able to receive a response. This is what I expected to be able to do and happens for me in Firefox, Chrome, and IE.

One way to kind of get around this caveat is having a local php file with will call the data via curl and respond the response to your javascript. (Kind of restated what you said you knew already.)

Ryan Matthews
  • 1,043
  • 9
  • 28
  • Why do you expect this behaviour? If the headers are set that the request isn't valid, I would kinda expect the script itself to not-run. Something like: set header "not allowed" and then send something negative / false back. But apparently this does not happen :) – Nanne May 09 '11 at 15:47
  • I have used this ability to send data such as a link to a different system. This link is used to download the file to a separate server but requires no response to the script. The strange thing I have noticed is that the headers which are returned have the proper content length but it just strips out the data. I would expect it to block it all together so I don't even see the header response. – Ryan Matthews May 09 '11 at 17:19
  • yep, that is exactly what I see. Didn't expect it though :) – Nanne May 09 '11 at 17:53
0
  1. Yes, it's correct and you won't be able to do that unless you use any proxy.

  2. No, request won't go to the external IP as soon as there is such limitation.

Umair A.
  • 6,690
  • 20
  • 83
  • 130
  • although there was a hack for FireFox which I had once tried to overcome this problem for testing purposes. I found a solution for Chrome too but it never worked. – Umair A. May 09 '11 at 15:21
  • Well, that means that point 2 is a bug, because I can confirm it does arrive at the IP. – Nanne May 09 '11 at 15:37
  • You're incorrect on #2 since that is allowed - otherwise solutions such as the access-control headers (linked to in my answer) would not work. Cross domain restrictions are 'artificial' in the sense that they were added to browsers as a security measure and not because of an inherent inability to make such requests. As such, requests and responses will both appear over the wire, it's just your JS code that will not see the response because the browser will stop it. – no.good.at.coding May 09 '11 at 15:42
  • Ah my bad then. I used common sense. – Umair A. May 09 '11 at 15:58