Thanks to an edit in my /etc/hsots file, I have two domains pointed to my localhost
127.0.0.1 dom1.com
127.0.0.1 www.dom1.com
127.0.0.1 dom2.com
127.0.0.1 www.dom2.com
I've got my local apache set up to host each of these domains from separate locations (separate conf files, etc.).
I've set up both domains with autentication. The page dom2.com/secret.php requires a user to be logged in so I login to dom2.com and visit this page. The output when you are logged in looks like this:
Your secret info: FOOBAR
If you are not logged in, it says "you are not logged in." Once I log in, though, I can open brand new browser windows in Firefox and go directly to that page and always see the FOOBAR message because the session cookie has not expired.
The problem I have is when I try to create an AJAX request on dom1.com that requests this page to take advantage of the authenticated session. For instance, I have this script assigned to a button on dom1.com/test.php
<script type="text/javascript">
$(function() {
$("#csrf-launch").click(function (e) {
$.ajax({
cache: false,
crossDomain: true,
type: "GET",
async : true,
dataType: "text",
url: "http://dom2.com/secret.php",
complete : function(jqXHR, str, str2) {
console.log('complete:' + str);
console.log('response:' + jqXHR.responseText);
}
});
});
});
</script>
The output is:
complete: success
response: you are not logged in
Why does the AJAX request not send the session cookie such that the request is considered authenticated/logged-in? This is the request header that I see in Firebug for the AJAX request:
GET /csrf-secret.php?_=1459884582040 HTTP/1.1
Host: dom2.com
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0
Accept: text/plain, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Referer: http://dom1.com/test.php
Origin: http://dom1.com
Connection: keep-alive
Note that in my dom2.com/secret.php file, I send a variety of headers to try and permit COR request:
header('Content-Type: text/plain');
header("Access-Control-Allow-Origin: http://dom1.com");
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Allow-Headers: x-requested-with');
header("Access-Control-Allow-Methods: GET, POST", TRUE);
if (!$this->logged_in) {
die("You are not logged in ");
} else {
echo "Your secret info: FOOBAR\n";
die();
}
I've also tried a non-jQuery approach using basic Javascript (described here) that also doesn't work:
<script type="text/javascript">
function createCORSRequest(method, url) {
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
// Check if the XMLHttpRequest object has a "withCredentials" property.
// "withCredentials" only exists on XMLHTTPRequest2 objects.
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined") {
// Otherwise, check if XDomainRequest.
// XDomainRequest only exists in IE, and is IE's way of making CORS requests.
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
// Otherwise, CORS is not supported by the browser.
xhr = null;
}
return xhr;
}
// Make the actual CORS request.
function makeCorsRequest() {
var url = 'http://dom2.com/secret.php';
var xhr = createCORSRequest('GET', url);
if (!xhr) {
alert('CORS not supported');
return;
}
// Response handlers.
xhr.onload = function() {
var text = xhr.responseText;
alert('Response from CORS request to ' + url + ': ' + text);
};
xhr.onerror = function() {
alert('Woops, there was an error making the request.');
};
xhr.withCredentials = true;
xhr.send();
}
$(function() {
$("#csrf-launch").click(function (e) {
makeCorsRequest();
});
});
</script>
The request and result are essentially the same. No cookies in the request header, "you are not logged in" for a response.