PHP isn't saving session when it's an ajax call - php

Hi all,
i'm testing out a service for internal ads on our website...
I need to save internal session (PHP) to know what ads have been displayed and some other protection stuff...
The problem is that if i access to the API throught webbrowser GET or POST it does session (and saves the cookie of php session), but if i use jQuery.ajax() method it doesn't save it...
My link for tests is http://search.microdual.com
(this is because i wanted a customized google search on my laptop :p)
I suggest you to use firebug to take a look at the javascript code. (PHP code isn't needed because it is working on clicks...)
To simplify the debugging, i print out on response json array from server the session id on the var {id_sessao:"..."}...
Thanks in advance,
José Moreira
EDIT:
Headers from server:
Date Wed, 08 Sep 2010 11:24:48 GMT
Server Apache/2.2.8 (Ubuntu)
P3P CP="NOI NID ADMa OUR IND UNI COM NAV"
Cache-Control private, must-revalidate
Access-Control-Allow-Orig... *
Access-Control-Allow-Cred... true
Access-Control-Allow-Meth... OPTIONS, GET, POST
Access-Control-Allow-Head... Content-Type, Depth, User-Agent, X-File-Size, X-Requested-With, If-Modified-Since, X-File-Name, Cache-Control
Set-Cookie SN4b55935921bde=7ad280272050b4b44f17769909fd6f34; path=/ SN4b55935921bde=7ad280272050b4b44f17769909fd6f34; path=/
Keep-Alive timeout=15, max=97
Connection Keep-Alive
Transfer-Encoding chunked
Content-Type text/html; charset=UTF-8
Headers from the jQuery Ajax request:
Host www.microdual.com
User-Agent Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; pt-PT; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8
Accept application/json, text/javascript
Accept-Language pt-pt,pt;q=0.8,en;q=0.5,en-us;q=0.3
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 115
Connection keep-alive
Content-Type application/x-www-form-urlencoded; charset=UTF-8
Referer http://search.microdual.com/
Content-Length 29
Origin http://search.microdual.com
Pragma no-cache
Cache-Control no-cache
Where is the cookie control on the jQuery Ajax Request?

The problem is probably that your parent document is on search.microdual.com, and you are requesting a script from www.microdual.com. The session cookie isn't transported across domains.
If you are not using document.domain - I don't see it anywhere? - you will also have the additional problem that the AJAX call fails due to the Single Origin Policy.
To fix the cookie issue, you could either
set the cookie's domain to .microdual.com so it works in both sub-domains
carry the session across manually in the URL (?sessionid=xxxxx) and continue the session using session_id("xxxxx");.
put both scripts on the same sub-domain (search.microdual.com)
The latter would be the easiest way.

Related

CORS Headers are altered in the browser resulting in content becoming blocked

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?
The issue could be similar as my answer here:
The server is not configured to respond to OPTIONS requests with the correct "Access-Control-Allow-" headers.
Opening the url in a new Tab is a GET request and is working because it is not making a preflight request, as it meets the criteria to be a simple request as defined by the CORS documentation
On the other hand, the ajax request is a POST request and meets the criteria to be a Preflighted request, meaning a preflight OPTIONS request should be made first.
In short, you have correctly setup the CORS response headers, but the server is not configured to add these headers for OPTIONS method requests.
The solution is to handle OPTIONS requests on the server code with a 2xx response and add the **Access-Control-Allow- as you do for GET and POST requests. Keep in mind that OPTIONS requests do not include any parameters, so this should be done before any validation or request parsing.
Moreover, according to Access-Control-Allow-Origin documentation:
If the server specifies a single origin rather than the "*" wildcard, then the server should also include Origin in the Vary response header — to indicate to clients that server responses will differ based on the value of the Origin request header.
So set the Vary response header also:
eg at the top of you script try:
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Credentials: true");
header("Vary: Origin");
exit;
}
References
Preflighted requests
response for preflight 403 forbidden
The problem is that you use header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']); (BTW: not very recommended) and you get the wrong header. I bet on one of the reasons:
The web server overwrites the headers.
The browser uses cache, although it should not. (BFC).
You did not upload the updated code to the requesting server.
Let's start from the end.
Do not believe herself, verify. (Not once did I look, we do not work, and then came the reflection that I did not upload changes :) ).
Turn off the cache in the browser debugger. (you must have open debugger) If this is a problem and the function is to be available in the pool, add timestamp to the request.
Check the configuration of nginx / apache / server panel
Are you aware that the construction used by you is synonymous with Access-Control-Allow-Origin: *? You should check HTTP_ORIGIN if it belongs to the allowed pool.

PHP cookie-bases session swapping in phorum

I'm experiencing a strange error in my phorum server - seemingly at random, some users will be swapped with each other, and find themselves fully logged in as one another, with complete access to one another's accounts. I've experienced this bug myself once but cannot recreate it.
Phorum is configured to track sessions via cookie, with the session hashes also stored in the user database. I've confirmed the database is intact and there aren't session ID collisions happening.
You can see the source for phorum's authentication and session management here, it's fairly straightforward. Sessions are only created via log-in or from existing cookies so my working theory (after talking to a phorum developer) is that there is some sort of caching issue on the server. There's a known caching issue that affects ASP (see here or here for examples) but my server is a Linux server running Apache 2.4, MySQL (technically MariaDB 10.1 + InnoDB) and PHP 5.6. Is anyone aware of how this might be happening? I've been plugging away at this for over a week and have made little progress other than confirming the lack of bugs in the phorum session code.
The only clue I have to go on is that the session swapping started on the same day my hosting service took down (and restored) their file servers. They said they don't see how that could be responsible, however.
EDIT #1: I am adding some request and response headers.
Here is the response for an initial GET to get a list of forums.
General
Request URL: https://www.example.com/forum/list.php?11 Request
Method: GET Status Code: 200 Remote Address: x.x.x.x:443
Referrer Policy: no-referrer-when-downgrade
Response Headers
content-encoding: gzip content-type: text/html;
charset=UTF-8 date: Mon, 07 May 2018 20:23:08 GMT server: Apache
set-cookie: phorum_session_v5=35%3A412b7c329cc8741de88532342df9; expires=Tue, 08-May-2018 20:23:08 GMT; Max-Age=86400; path=/
status: 200 vary: Accept-Encoding via: e3s
Request Headers
:authority: www.example.com
:method: GET
:path: /forum/list.php?11
:scheme: https
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8
accept-encoding: gzip, deflate, br accept-language: en-US,en;q=0.9
cache-control: max-age=0
cookie: phorum_session_v5=35%3A412b7c329cc8741de88532342df9;
referer: https://www.example.com/forum/addon.php?11,module=user_list
upgrade-insecure-requests: 1 user-agent: Mozilla/5.0 (Windows NT 10.0;
Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/66.0.3359.139 Safari/537.36
And here is a follow-up Ajax call:
General
Request URL: https://www.example.com/forum/ajax.php?client
Request Method: GET Status Code: 200 (from memory cache)
Remote Address: x.x.x.x:443 Referrer Policy: no-referrer-when-downgrade
Response Headers
age: 734
cache-control: must-revalidate
content-encoding: gzip
content-length: 2862
content-type: text/javascript;charset=UTF-8
date: Mon, 07 May 2018 18:29:37 GMT
expires: Tue, 08 May 2018 02:29:37 GMT
pragma: cache
server: Apache
status: 200
vary: Accept-Encoding
via: e2s
#Sammitch was correct - phorum was not setting cache-control in the headers for most of my pages. This was causing my hosting service's own caching system to cache responses that included session cookies.
I fixed this by changing my .htaccess file as described here: https://stackoverflow.com/a/7664157/1411376
This seems to work for my server config, since the php code (phorum) had no code that set cache-control (except for ajax requests).

varnish not work only for one web site

I have a server with more site , after install varnish I tested if cache works, but for one web site not work varnish (have response of max-age=0). If I try to insert a simple php page (not correlated to main website) in same folder of this website, the response works.
This is a header when try :
HTTP/1.1 200 OK
Server: Apache/2.2.27 (Unix) mod_ssl/2.2.27 OpenSSL/1.0.1e-fips
X-Powered-By: PHP/5.2.17
Set-Cookie: PHPSESSID=ragejao4sm1kckjn1trvap3ft0; path=/
Vary: User-Agent,Accept-Encoding
Content-Encoding: gzip
Content-Type: text/html
Cache-Control: max_age=8600
magicmarker: 1
Content-Length: 11863
Accept-Ranges: bytes
Date: Fri, 12 Jun 2015 12:28:15 GMT
X-Varnish: 1250916100
Age: 0
Via: 1.1 varnish
Connection: keep-alive
Varnish by default doesn't cache responses where cookies are set.
If you want to change this behaviour you need to consider how the cookie is being used (it looks like a session cookie) and either use the session id as part of the cache hash (ie so other users don't get a cached response from someone else's session) or use something like ESI to allow the "common" parts of the page to be cached while the session specific parts are fetched independently.
http://www.varnish-cache.org/trac/wiki/VCLExampleCacheCookies
https://www.varnish-cache.org/trac/wiki/ESIfeatures

html/php: Changing images order by swapping filenames doesn't take immediate effect

I have following problem that's bugging my mind completely. I have to take over this cms from someone who doesn't want to care for it anymore and is giving no support whatsoever.
Situation is as follows: on the site there are several photo albums which are populated by reading a directory in php. All is good there, pictures are shown in the order they are read. In the management system, these pictures can be changed in order by an up or down-button. The way this is done is by swapping the image's filenames. This works, when I change the order for an image i can see server-side the filenames have actually been swapped.
This is however not the case on the site, at least not immediately: it takes an average of 10 minutes to see the images swapped there. Ofcourse, my client can't work like this, and he claims it has always worked before. I have tried to turn off caching browser-side, this hasn't helped. I can also note the changes take effect on the same time in IE and FF. I tried several ways of turning off cache server-side in php too, also to no avail.
Is there any other place where I should be looking or could there be another reason why these changes don't take effect immediately?
In addition, changes i make to javascript don't get picked up immediately too. I installed fiddler and this is the request header for that js file:
GET http://www.nobel-country-gite.be/admin/modules/Photoalbum/js/album.js HTTP/1.1
Accept: application/javascript, /;q=0.8
Referer: http://www.nobel-country-gite.be/admin/index.php?page=pic&album=24
Accept-Language: nl-BE
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
If-Modified-Since: Wed, 27 May 2015 15:55:12 GMT
If-None-Match: "ba1248f5-138b-5171244a92f66"
DNT: 1
Host: www.nobel-country-gite.be
Pragma: no-cache
Cookie: __utmc=39679548; __utma=39679548.1608184058.1429963360.1432662247.1432664636.7; __utmz=39679548.1429963360.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmc=1; PHPSESSID=7uge1ltg2rc11q63untthrc5s1; __utma=1.459796341.1429963360.1432662247.1432664636.7; __utmz=1.1429963360.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)
Response header is as follows:
HTTP/1.1 304 Not Modified
Server: Apache
Last-Modified: Wed, 27 May 2015 15:55:12 GMT
ETag: "ba1248f5-138b-5171244a92f66"
Vary: Accept-Encoding
Content-Type: application/javascript
Date: Wed, 27 May 2015 16:57:55 GMT
X-Varnish: 1826689067 1825041752
Age: 556
Via: 1.1 varnish
Connection: keep-alive
I would expect the answer to be different instead of 'not modified'?
Edit - upon waiting a few minutes and refreshing the page again, the response for this file is what is expected:
HTTP/1.1 200 OK
Server: Apache
Last-Modified: Wed, 27 May 2015 16:57:30 GMT
ETag: "ba1248f5-1387-51713237ac28e"
Vary: Accept-Encoding
Content-Type: application/javascript
Transfer-Encoding: chunked
Date: Wed, 27 May 2015 17:03:43 GMT
X-Varnish: 1827728442
Age: 0
Via: 1.1 varnish
Connection: keep-alive
I couldn't help but notice you are using Varnish (indicated by the X-Varnish response header). Varnish is a caching reverse proxy, which means your pages are not just being cached by the browser, but also on the server (by Varnish). Your browser connects to Varnish, and Varnish connects to your Apache backend.
The first response header includes "Age: 556" - that's the cached version's age in seconds (almost 10 minutes). Then the age comes across as "0" when the page refreshes - that's because Varnish has updated its cache. Probably you can access the page over HTTPS to see your changes immediately reflected (Varnish doesn't work for HTTPS and most people don't bother setting up an HTTPS cache), or you can generally add garbage GET parameters to your URL (e.g. "?bogus=123") to force Varnish to re-fetch the page (this won't make other users see the new version, since they'll be accessing via the normal URLs).
Fixes: You can use varnishadm to ban (expire) certain URLs in Varnish when you've made a change; you can modify the "Cache-Control" or "Expires" headers your CMS/Apache (via PHP, .htaccess, etc.) produces to reduce cache time (Varnish completely respects cache control headers in its caching strategy); you can change Varnish's behavior by editing the relevant VCL (usually "default.vcl"); or you can accept that caches are generally good (they save a lot of time and resources in generating the response), and maybe a 10 minute delay is an acceptable trade-off.

Display HTTP Response on Webpage using PHP

I am looking to put together a website that displays the full HTTP Request Headers and HTTP Response Headers for the loading of the page itself. For instance. If someone browses to http://example.com/index.php , I want the following to display:
HTTP Request
GET /index.php HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
HTTP Response
HTTP/1.1 200 OK
Date: Mon, 21 Dec 2011 10:20:46 GMT
Server: Apache/2.2.15 (Red Hat)
X-Powered-By: PHP/5.3.3
Content-Length: 1169
Connection: close
Content-Type: text/html; charset=UTF-8
We were able to get the Request header to display fairly simply using the following PHP code:
print $_SERVER['REQUEST_METHOD']." ".$_SERVER['REQUEST_URI']." ".$_SERVER['SERVER_PROTOCOL']."<br>";
foreach (apache_request_headers() as $name => $value)
echo "$name: $value<br>";
But are having some difficulties with the HTTP Response header. Anyone have any ideas of how we can do this? It does not have to be PHP if you have a method that works in Perle or CGI or whatever.
To be clear, I don't mean to set the HTTP Response to anything specific, only display the response served by the web server to load the page.
You want to use headers_list()
http://www.php.net/manual/en/function.headers-list.php
headers_list() will return a list of headers to be sent to the browser / client. To determine whether or not these headers have been sent yet, use headers_sent().
Well here is the issue, the response header is generated after the PHP (or any server-side language for that matter) has already completed its job.
To put it in english its like the post man handing you a letter and you asking him to explain how the process of handing you the letter went. He will probably just look at you dumb.
You will need a client-side language (ie. JavaScript) to perform this task.
Use PHP to get the headers sent to the web Server.
http://www.php.net/manual/en/function.apache-request-headers.php
Use JavaScript to get headers sent by the web server. I would suggest using jQuery for that.
http://api.jquery.com/jQuery.ajax/#jqXHR
This way you are sure that you get all the headers which are either received by the web server or the browser.
Check out get_headers in PHP Manual

Categories