Browser Sends Two Cookies - PHP's Session Handler Reads Wrong One - php

For a period of time cookies were set on a single site with different values for the domain. This resulted in some people having cookies with the same name set for both .www.domain.com and .domain.com. The site is intended to be accessed as www.domain.com. This is accomplished with .htaccess rules.
The code will use .domain.com. now for the session.cookie_domain going forward.
The issue I am having is that when both cookies exist the browser sends both (both are valid). I see this is so in the headers and also when dumping out apache_request_headers(), however, when I dump out $_COOKIE I see just one of them.
["Cookie"]=>
string(74) "foobar=hkej4qdnq5kismiq3kl07qv6k2; foobar=ocvn7anlu2f2k2l37nl9ou3c21"
And then...
array(1) { ["foobar"]=> string(26) "hkej4qdnq5kismiq3kl07qv6k2" }
My session interface read($id) method is checking the old cookie and not the one we set on login.
What is the best way to address this? I am thinking I could just change the session name/identifier and start fresh. Or maybe evaluate the Apache headers in my read implementation. I have not found much that is relevant in searching the web, just a bunch of fluff from w3schools polluting the results, so I thought this might be a good one to post here.

I had the same problem and solved it by changing the session name.
PHP allows you to access the variable $_SERVER["HTTP_COOKIE"] and parse it yourself. This allows you to access both values, of the cookie, but you can still not tell apart the correct and the wrong cookie.
Unless those cookies contain really valuable data, I would not care about the old values and just start new.

Just change the session name from PHPSESSID to SITESESSID or something else of your choice. This will make sure that your application ignores the old cookie all together. If the lifetime of your session is 0, then its a SESSION Cookie(Gets deleted when the browser is closed), in such case you can change the session name back to PHPSESSID after a few days or a month of implementation since you will be sure that no one has the old cookie.
BTW: The browser isn't sending two cookies. It's just your old session cookie still alive.

Related

Is it possible to prevent php session from destroying when you close browser?

We want to use sessions instead of cookies for keeping track of a few things. However, when I close my browser, and I reopen a page to echo a session var, it doesn't exist (which is how it is suppose to be). Is it possible to prevent this from happening with some magic or anything?
This is not a duplicate question, all I see are people wanting to destroy sessions, I want to do the opposite and retain the session for as long as possible.
Any knowledge would be appreciated.
The right way of doing this is with a database, you can mimic or control php sessions and store them in a database instead of in a file ( as normal ). Then once you have control of the data you can base renewing session via the ip address or better yet by login.
So say a user logs in and then you need to store some data, you store that in the session but php will store it in your database table ( when configured correctly ). Latter the user comes back, initially any visitor would get a fresh session, however once they login you would be able to retrieve the past session they had. You generally don't have much control on if or when a client will delete expired cookies.
This topic is too extensive to put just a few pieces of example code but I did find this small article on the topic.
http://culttt.com/2013/02/04/how-to-save-php-sessions-to-a-database/
The guts of it is to use this function, session_set_save_handler
http://php.net/manual/en/function.session-set-save-handler.php
Once you have control of the data you can do whatever you want, however I would caution you about relying only on the IP address and it would be preferable to use a login system for something like this to prevent serving the session up to the wrong visitor.
You cannot reliably control what happens on the client side, even using a separate cookie would not be reliable and would have the disadvantage of storing data on the client where it could be accessed instead of keeping it on your server. Sessions are controlled by cookies but the data in them remains on your server, the cookie just identifies the client.
As a side note, I personally dislike using sessions at all. It may be possible to store what you need in the url, then it can be bookmarked. The classic example would be input for a search form ( via $_GET ) or for paging purposes. There is nothing wrong with doing this if it's not secure data. The problem with sessions is if the data is for a page such as my "classic example" or for paging you get only one session, so you would only be able to have one set of search data at a time, in the url you could have several sets of search data open at once. That said it does largely depend on what you need to save or persist.
Reset the session cookie manually.
$lifetime=60*60; // duration in seconds
session_start();
setcookie(session_name(),session_id(),time()+$lifetime);
You can use session.gc_maxlifetime and session_set_cookie_params, i.e.:
// server should keep session data for AT LEAST 1 Year
ini_set('session.gc_maxlifetime', 3600 * 24 * 365);
// each client should remember their session id for EXACTLY 1 Year
session_set_cookie_params(3600 * 24 * 365);
session_start();
Note:
You can also change the session options globally by editing php.ini -
Session configuration options
PHP sessions use session cookies. Browsers have their own ways of dealing with them but they all consider them to be trash if you close the browser.
Session cookies are not and can not be made persistent. If you need persistent cookies, just use a regular cookie to save a user identification code that your server would recognize, and save their session information in a database or flat file indexed on that id code.
Note that accumulating sessions on the server progressively causes important performance and security concerns.
Note on other answers: All of them mention ways to extend the session cookie expiration which will not overcome the regular behavior when you close your browser window.

php session and cookies

I want to have sessions persist the browser closing
So I used
session_set_cookie_params(86400 * 60, '/', 'my.domain.com', true, true);
to send a persistent cookie to the client (also with the secure flag as this is a SSL site)
which is valid for 2 months.
However, I see that after x minutes of inactivity the session variables are cleared on the server.
How can I avoid that? Essentially, I want the session variables to be stored until the cookie
becomes invalid
Thanks
Set the session.gc_maxlifetime configuration property.
The documentation is rather sparse when it comes to acceptable values for it, but I wouldn't want to go as high as two months.
You'd usually be better off storing the important data in a database, and adding it to a session when one is created with a remember me cookie.
Leave sessions for actual sessions.
With sessions you are looking at two things. The time until garbage collection cleans up the session on the server, and the time until the cookie expires.
You only changed the cookie expiration, the session will still get cleaned up. However extending the session is not a great way to solve this. Your code could change and you may end up with users having a broken session. You may need to use some sort of shared session storage like memcached that will delete the storage after a certain max time anyway.
So the way to solve this is to generate a unique one time cookie that can be used as an alternative login key. This key will allow a user to login similar to a username/password. Once its used, a new one gets regenerated.
Session variables will persist as commented below, but unless you change their default behavior, they expire when the session ends (i.e. when the browser is closed).
For what you're trying to accomplish, you should store your values in $_COOKIE variables, not $_SESSION variables.
See this article: http://buildinternet.com/2010/07/when-to-use-_session-vs-_cookie/

Intermitant Sessions

I have a site I'm deploying and I've hit a problem. I was testing my code in a sub-directory of my clients hosting package and everything seemed fine. However I've moved the folders/files to the site root and now I'm intermittently losing all session data.
I've taken a look with LiveHeaders in Firefox and these cookies are being set:
Cookie: __utma=196298984.443251570.1275554915.1275554915.1275557276.2;
__utmz=196298984.1275554915.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none);
__utmb=196298984.188.10.1275557276; PHPSESSID=3f5a363de3b7ec6084c7fdf90bec78a8;
__utmc=196298984
and
Cookie: __utma=196298984.443251570.1275554915.1275554915.1275557276.2; _utmz=196298984.1275554915.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none);
__utmb=196298984.189.10.1275557276; PHPSESSID=3f5a363de3b7ec6084c7fdf90bec78a8;
__utmc=196298984
I'm by no means an expert on headers so if you need other information, I should be able to get it.
For a session to work, two elements have to both be working:
First, the browser must send the same PHPSESSID cookie with every request. The session ID will change from one session to another, so if you login tomorrow (or later today, or in a different browser, et cetera) you'll get a different ID than you have now, but during a single session the ID should not be changing.
Second, the server must be able to access the same files associated with that ID during every request. By default, PHP stores that information in the /tmp/ directory. If you have access, you could even poke around there and see what's getting stored.
The first issue is easiest to test for. Take a look at what cookies are being sent while the session is working, and then check again after the session stops working and see if the PHPSESSID has changed. The most likely cause for behavior like this would be a poorly set local computer clock, poor timeout settings on the session, et cetera.
The second issue is a bit trickier. If your browser is sending the right cookie with every request, but PHP can't access the file with information about that session, the problem is with the server. You might consider storing your sessions in a database (if you're using one anyway), which is easily done with code in the PHP manual.
A couple of things that come to my mind:
1 : Make sure that if your session is being created on www.abc.com, then all browsing happens on exactly that domain, if some pages are being sent to abc.com instead of www.abc.com, this is likely to cause session/cookie problems.
2 : also make sure that session_start instruction is available on top of ALL pages.

How to re-initialize a session in PHP?

I am attempting to integrate an existing payment platform into my webshop. After making a succesful transaction, the payment platform sends a request to an URL in my application with the transaction ID included in the query parameters.
However, I need to do some post-processing like sending an order confirmation, etc. In order to do this, I'd need access to the user's session, since a lot of order-related information is stored there. To do this, I include the session_id in the intial request XML and do the following after the transaction is complete:
$sessionId = 'foo'; // the sessionId is succesfully retrieved from the XML response
session_id($sessionId);
session_start();
The above code works fine, but $_SESSION is still empty. Am I overlooking something or this simply not possible?
EDIT:
Thanks for all the answers. The problem has not been solved yet. As said, the strange thing is that I can succesfully start a new session using the session_id that belongs to the user that placed the order. Any other ideas?
Not really what you ask for, but don't you need to persist the order into database before you send the customer to the payment-service? It's better to rely on persisted data in your post-processing of the order when you receive the confirmation of the payment.
Relying on sessions is not reliable since you will have no idea on how long this confirmation will take (usually it's instant, but in rare cases this will have a delay).
Also, in the event of your webserver restarting during this time span, will make you lose relevant data.
A third issue is if you have a load-balancing solution, with individual session-managment (very common) then you will have no guarantee that the payment-server and your client will reach the same webserver (since stickiness is usually source-ip based).
I will venture to guess that since domains are different from where the session is set to where you are trying to read it, php is playing it safe and not retrieving session data set by a different domain. It does so in an effort to preserve security in case somebody were to guess session ID and hijack the data.
Workaround for this, assuming the exchange happens on the same physical disk, is to temporary write order data to a serialized (and possibly encrypted depending on wether or not full credit card number is being tracked, which is a whole another story) file that once read by the receiving end is promptly removed.
In essence all that does is duplicates the functionality that you are trying to get out of sessions without annoying security side-effects.
Many thanks for all the replies.
Smazurov's answer got me thinking and made me overlook my PHP configuration once more.
PHP's default behaviour is not to encrypt the session-related data, which should make it possible to read out the session data after restarting an old session from another client. However, I use Suhosin to patch and prevent some security issues. Suhosin's default behaviour is to encrypt session data based on the User Agent, making it a lot harder to read out other people's sessions.
This was also the cause of my problems; disabling this behaviour has solved the issue.
Make sure you're closing the current session before you attempt to start the new one. So you should be doing:
$id = 'abc123';
session_write_close();
session_id($id);
session_start();
Dirty, but has worked for me:
Tell the payment gateway to use
http://yourdomain.com/callbackurl.php?PHPSESSID=SESSIONIDHERE
PHP uses that method of passing a session around itself if you set certain config vars (session.use_trans_sid), and it seems to work even if PHP has been told not to do that. Its certainly always worked for me.
Edit:
Your problem may be that you have session.auto_start set to true - so the session is starting automatically using whatever ID it generates, before your code runs.
How about do it in another PHP page, and you do a iframe include / redirect user to the second page?
I'm not sure the exact length of time between your transaction and your check; but it certainly seems that your session cookie has expired. Sessions expire usually after 45 minutes or so by default. This is to free up more uniqid's for php to use and prevent potential session hijacking.
I'm not sure if you have a custom session handler and whether it's stored in the database but guessing from your posts and comments on this page I would assume it is stored in server side cookies.
Now the solution to your problem, would be to bite the bullet and store the necessary data in the database and access it via the session id, even if it means creating another table to sit along side your orders table.
If however you are doing the action immediately then the other explanation is that either the user logged out or committed an action which destroyed their session (removing the server side cookie).
You will see these cookies in your servers /tmp folder, try have a look for your cookie, it should be named 'sess' + $session_id.

In PHP will a session be created if a browser is not used

I have an API that is dependent on certain state information between requests. As an easy first version of the code, I am simply using PHP session's to store the state information instead of something more advanced (APC, memcache, DB). Throughout my initial testing in a web browser, everything worked perfectly. However, it seems that when clients try to connect through non-browser methods such as Curl or wget, the state information is not being preserved.
Will a PHP session only be created if a browser is requesting the page? I am explicitly starting the session with session_start() as well as naming it before hand with session_name().
An added note. I learned that one of the major problems I was having was that I was naming the session instead of setting the session id via session_id($id); My intention in using session_name() was to retrieve the same session that was previously created, and the correct way to do this is by setting the session_id not the session_name.
It seems that session information will be persisted on the server as noted below (THANK YOU). But to keep this you must pass the session id, or, as in my case, any other id that would uniquely identify the user. Use this id as the session_id and your sessions will function as expected.
Session Cookies
Remember that HTTP is stateless, so sessions are tracked on your server, but the client has to identify itself with each request. When you declare session_start(), your browser is usually setting a cookie (the "PHP Session Id"), and then identifying itself by sending the cookie value with each request. When a script is called using a request with a session value, then the session_start() function will try to look up the session. To prove this to yourself, notice that sessions die when you clear your cookies.. many will die even as soon as you quit the browser, if the cookie is a "session" cookie (a temporary one). You mentioned that you're naming the session.. take a look in your browser cookies and see if you can find a cookie with the same name.
All of this is to say that cookies are playing an active role in your sessions, so if the client doesn't support cookies, then you can't do a session the way you're currently doing it.. at least not for those alternative clients. A session will be created on the server; the question is whether or not the client is participating.
If cookies aren't an option for your client, you're going to have to find another way to pass a session id to the server. This can be done in the query string, for example, although it's a considered a bit less private to send a session id in this way.
mysite.com?PHPSESSID=10alksdjfq9e
How do to this specifically may vary with your version of PHP, but it's basically just a configuration. If the proper runtime options are set, PHP will transparently add the session id as a query parameter to links on the page (same-source only, of course). You can find the specifics for setting that up on the PHP website.
Sidenote: Years ago, this was a common problem when attempting to implement a session. Cookies were newer and many people were turning off the cookie support in their browsers because of purported security concerns.
Sidenote: #Uberfuzzy makes a good point- Using sessions with curl or wget is actually possible. The problem is that it's less automatic. A user might dump header values into a file and use the values on future requests. curl has some "cookie awareness" flags, which allow you to handle this more easily, but you still must explicitly do it. Then again, you could use this to your advantage. If curl is available on your alternative client, then you can plausibly make the call yourself, using the cookie awareness flags. Refer to the curl manual.
If you call session_start(), then a session will be created if the client isn't in an existing one. If the client doesn't support (or is configured to ignore) the cookies or querystring mechanism used to maintain the session, a new session will be created on every request.
This may bloat your session storage mechanism with unused sessions.
It might be a better idea to only call session_start() when you have something to store in the session (e.g. user login, or something else that robots aren't likely to do), if you feel this is likely to be a problem.
Will a PHP session only be created if a browser is requesting the page?
Short answer: Yes. Sessions were created specifically to solve the HTTP stateless problem by leveraging browser features. APC, memcached, DB, etc. don't matter. Those are just storage methods for the session, and will suffer from the same problem.
Longer answer: The concept of sessions were created to account for the fact that HTTP is a stateless protocol, and it turns out that state's pretty important for a wide variety of software applications.
The most common way of implementing sessions is with cookies. PHP sends the session ID in a cookie, and the browser sends the cookie with the session ID back. This ID is used on the server to find whatever information you've stored in the session. PHP has the capacity to include and read a session ID at the end of a URLs, but this assumes that users will navigate to pages on your site/application by clicking links that include a generated session ID.
In your specific case, it is possible to use cookies with curl (and possibly wget). Curl is a web browser, just one without a GUI. If it's the command line curl program you're using (as opposed to the C library, PHP extension,etc.) read up on the following options
-b/--cookie
-c/--cookie-jar
-j/--junk-session-cookies

Categories