Update 2 (A complete set of logs)
From Client's Perspective
Request headers:
POST /dev/micro_server.php HTTP/1.1 Host: production-server.com
Connection: keep-alive
Content-Length: 86
Pragma: no-cache
Cache-Control: no-cache
Accept: text/html, /; q=0.01
Origin: https://debug.dev
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36 OPR/58.0.3135.90
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: https://debug.dev/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Cookie: debugger_session=iq4tbdk374mtvodsd3edcf2jq5
Response headers:
HTTP/1.1 200 OK
Server: nginx/1.4.6 (Ubuntu)
Date: Tue, 12 Mar 2019 12:01:27 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/5.5.9-1ubuntu4.17
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Origin: https://production-server.com
Access-Control-Allow-Credentials: true
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Encoding: gzip
Console Error:
Access to XMLHttpRequest at 'https://production-server.com/dev/micro_server.php' from origin 'https://debug.dev' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'https://production-server.com' that is not equal to the supplied origin.
Console Warning:
Cross-Origin Read Blocking (CORB) blocked cross-origin response https://daikai.no/dev/micro_server.php with MIME type text/html. See https://www.chromestatus.com/feature/5629709824032768 for more details.
From Server's Perspective
This is what the server says it has received and sent (check the code that does the logging in update 1):
Array
(
[req] => Array
(
...
[HTTP_ORIGIN] => https://debug.dev
...
)
[rsp] => Array
(
[0] => X-Powered-By: PHP/5.5.9-1ubuntu4.17
[1] => Access-Control-Allow-Origin: https://debug.dev
[2] => Access-Control-Allow-Methods: GET, POST, OPTIONS
[3] => Access-Control-Allow-Credentials: true
)
)
Update
I have added some logging on the server and the script now begins with these lines:
# allow access from other domains
header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Credentials: true");
$all = [
'req' => $_SERVER,
'rsp' => headers_list()
];
$s = print_r($all, true);
$p = '/var/www/path/to/file_' . uniqid() . '.txt';
file_put_contents($p, $s);
With this I can confirm that the request arrives on the server with the correct Origin, AND the server sends back the correct CORS headers. Yet, the Access-Control-Allow-Origin
in the developer console is wrong and the request is blocked.
Here is a stripped down log obtained with the code above:
Array
(
[req] => Array
(
...
[HTTP_ORIGIN] => https://debug.dev
...
)
[rsp] => Array
(
[0] => X-Powered-By: PHP/5.5.9-1ubuntu4.17
[1] => Access-Control-Allow-Origin: https://debug.dev
[2] => Access-Control-Allow-Methods: GET, POST, OPTIONS
[3] => Access-Control-Allow-Credentials: true
)
)
Question
How and why does the Access-Control-Allow-Origin
is changed to https://production.com
when the actual header received is Access-Control-Allow-Origin: https://debug.dev
?
(Original Post)
Background
I have a web-based debug tool that I have installed on my local development machine. With an entry in my /etc/hosts I have assigned to it the domain debug.dev
. I have also added a local CA authority and have successfully created a SSL certificate for the domain name so now I can open https://debug.dev/
in my browser and the debug tool opens normally.
This tool is supposed to work with staging and production servers. So it needs to send AJAX requests to other domains. I have full control over those servers and I am sending back CORS headers from those servers like so:
header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
header("Access-Control-Allow-Credentials: true");
The Issue
Now I am facing a baffling situation in which when I send an AJAX request to the production server I get back Wrong CORS headers with the SERVER's domain like this:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://production-server.com
But if I right click and use Open in new tab the CORS headers are what they ought to be; i.e.
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://debug.dev
The only differences between the requests as far as I can see is that the first one is sent as an AJAX POST request and thus sends a HTTP_X_REQUESTED_WITH header whereas the second request is sent as an ordinary GET request. How could this result in a different CORS header be returned by the server?