I'm having problems with the PHP site I run at work where users are being logged out after a few minutes (the exact time varies, but it is frequent enough to be an issue), regardless of whether they have been actively using the site or not.
The difficulty is that I can't reproduce this problem, if I login as the same users using the same browser I don't get logged out, which suggests it is not a case of the site being completely broken. Unfortunately I don't have access to the user machines to run any traffic-sniffing software.
The things I have already checked are:
Asking users to try different browsers. This doesn't seem to solve the problem and isn't a long-term solution anyway as I can't dictate which browsers customers will use.
The server time is correct and in line with the user machines.
The user Apache runs as has permission to write to the session folder, and I can see the session files being created and their modification times being updated.
No output buffering functions are being used.
The problem is happening on a variety of pages which seem to have nothing in common (i.e. it's not that they all use AJAX, or update the database or some other reason).
Users only access their account from one machine, i.e. they don't do a bit of work on their laptop, switch to the desktop and then wonder why they've been logged out on their laptop (we don't allow multiple simultaneous logins for the same user).
The session settings in PHP are the Debian defaults, and haven't been changed in a .htaccess file or anywhere else. The main ones are:
session.cookie_lifetime 0
session.gc_divisor 100
session.gc_maxlifetime 1440
session.gc_probability 0
session.save_handler files
session.save_path /var/lib/php5
session.use_cookies On
Debian deletes sessions through a cron job instead of using PHP's garbage collector, which is why gc_probability is set to 0. The PHP version we're running is: PHP 5.2.6-1+lenny13 with Suhosin-Patch 0.9.6.2 (cli) (latest version in Lenny, we'll be upgrading to Squeeze soon but I don't think that is the cause of the problem).
We use Zend_Session to manage sessions, and an instance of Zend_Session_Namespace is created once on every page, thus automatically calling session_start(). Sessions are cleared by calling Zend_Session::destroy() on the logout page, so the only ways a user should be logged out are:
If they explicitly click the logout link (we log when this happens and it doesn't seem to be the case that browsing are pre-fetching the page and thus logging the user out).
If they leave the session inactive for more than 24 minutes, at which point Debian will probably delete their session (there's a cron job which runs every half hour deleting all sessions which have been unmodified for over 24 minutes).
If they close the browser, as their session cookie with an expiry time of 0 will be deleted.
The checks for seeing whether a user is logged in are:
They have a valid session (checked by seeing whether we can access $zsession->user_id).
There is a row in the sessions table which has a matching user ID and session ID, and this was last updated less than an hour ago. We delete this row on logout so that even if the session still exists on disk, no one can access that account without logging in.
Can anyone suggest other things I can try?
Edit: Some additional things I have tried based on comments left:
Setting session.cookie_domain: This seems to have very odd behaviour in PHP. If I do not set this variable and leave it as the default of '' (empty string), then a request for www.domain.com will produce a cookie of www.domain.com. However, if I set cookie_domain to 'www.domain.com', the domain for the cookie is '.www.domain.com' (notice leading dot, which means valid for everything below www.domain.com, e.g. subsite.www.domain.com).
Setting session.cookie_lifetime: PHP does not seem to update the expiry time on each request, so if I set cookie_lifetime to 3600 the cookie will expire one hour after the user first visits the site, even if they login and constantly use it.
Edit 2: Based on other things people have asked:
The site is hosted in a datacentre, on a separate VLAN. No one accessing the site is on the same network as the site.
There is no IP authentication used, nor is the IP address of the client used in any part of the session process (e.g. we don't attach the session to an IP address and block the user if their next request comes from a different IP).
Debian deletes sessions through a cron job instead of using PHP's garbage collector
That's very odd - and what is the code that runs in the cron job?
We delete this row on logout
I suggest you keep this for, say, 2 days after the session has expired / is deleted (but flag it as dead at the point where you currently delete it). Also, start logging the session id in your webserver logs.
In the end, the answer was to just scrap sessions and write my own very simple cookie code which differs from sessions in the following ways:
Stores a hash (bit like a session ID) in the database rather than in files.
Sets the cookie to expire in 3600 seconds from now (updated on each page) instead of 0 seconds (the latter seemed to cause problems for IE users, although I could never replicate it).
Only sends the cookie header when the user logs in or is logged in.
It's not an ideal situation as there's some reinventing the wheel going on, but my small solution seems to work where PHP sessions didn't, and having a working site is the most important thing.
I think you count change the value of
session.gc_maxlifetime
I also faced the same problem. I spent lots of time on it then i ask my web service provider and as he got the permission he changed that vale. Now it works fine.
Are there other php applications running on the same system (under different vhosts, for instance?)? Are they also saving sessions in /var/lib/php5?
If so, and one of those apps has a low session garbage-collection threshold, they will trash your app's session files.
I do a lot of ZF development, and if I'm using filesystem-based sessions, I stick them in application/data/session instead of the system default.
your session.gc_maxlifetime is set to 1440 ms which is only 1.44 seconds. shouldn't it be 1440000 ms = 24 minutes?
You could try setting session.use_only_cookies to a value of 1 and session.cookie_lifetime to a value of 1440 seconds.
is your site on different domains ? for example domain.com, www.domain.com, subdomain.domain.com ? if some pages are redirected to a different domain (www is considered a subdomain that is different) than the sessions will not work when the address changes
EDIT:
You must reproduce the problem. Ask your clients what kind of browser do they use, what action they do until they are logedout, are they viewing the same ip for the site as you do? (that is you are both in external networks or both in the same network with the site)
When you manage to find the problem, check the request/response headers when it the session works, and also when it does not work and then compare.
In the end I opted to send a Set-Cookie header on every page request, similar to what FlyBy suggested in one of the comments. The relevant code/logic now is (assuming session_start() has already been called):
$this->session_name = session_name();
$update_cookie = isset($_COOKIE[$this->session_name]); // Check if cookie already set, as PHP will send the first Set-Cookie when the session is started
$this->logged_in = $this->checkSession(); // Function which checks whether a valid (i.e. not timed-out) session row exists in the DB
if ($this->logged_in) {
$this->updateSession(); // Update the session row to the current time
if ($update_cookie) {
// Update the cookie expiry only if it existed before the login check
setcookie($this->session_name, $_COOKIE[$this->session_name], $this->time + 3600, '/');
}
}
I'm not sure why this worked, but I haven't had any further complaints and the number of logins has dropped drastically (no longer are there several logins in the logs for the same user within a few minutes of each other).
However, I will probably rewrite the code at some point to just use a database row and a cookie on the client, because the session functionality in PHP has so many variables that it's extremely difficult to work out what is causing the problem, and the session cookie handling is slightly different to how normal cookies are handled. In particular, you have to be careful with the setcookie function, because the default path for session cookies started by PHP is '/', but the default for setcookie is the current directory path, and these will not necessarily be the same.
Related
I am using sessions in an attempt to implement persistent logins for my users in a web application. The back-end is php 7.2 and apache, provided through Namecheap shared hosting.
I am setting a session cookie on the client with a "cookie_lifetime" and "gc_maxlifetime" of 604,800 seconds (one week). The server calls session_start() with these parameters and checks a $_SESSION key called "user_id" to see if the session_start() call has started an existing session (if the key is defined, the user is "logged in"). It does this every time the page is loaded. Everything works fine until about 40 minutes of inactivity have gone by, then the next page refresh and attempt to call session_start() and access any $_SESSION keys returns undefined for everything, despite the session cookie still showing an "Expires" value several days in the future in DevTools.
My understanding was that "cookie_lifetime", "gc_maxlifetime", and the associated "Expires" header for setting the client-side cookie would preserve session information for at least as long as the time specified, but this interaction is demonstrating that regardless of what I put in those fields, the $_SESSION superglobal will not return anything meaningful beyond ~40 minutes of inactivity.
Am I not understanding this correctly, or is there perhaps something wrong from a server configuration standpoint that is beyond the scope of the client-server application code?
I didn't fully get to the bottom of why this was occurring. I did reach out to the Namecheap support staff, however, and they told me their sessions were not malfunctioning in the same way after ~40 minutes; they continued to see session values that had been set several hours previously when they tried to recreate the issue using the same code and configuration as I was using.
I dug into the server configuration and reviewed the output of a phpinfo() dump and determined that the Registered save handlers were set to files user. I can't find out what the user component of that reflects, and maybe that's where the issue lies, but I was able to resolve the issue by explicitly specifying the session.save_path parameter rather than relying on the default (which was no value in the phpinfo output).
The support staff had said that the default location was /home/[user]/tmp/ and their sessions were showing up there, but mine were not. After adding the explicit save_path to php.ini, my sessions began to appear there and the ~40 minute expiration stopped occurring.
I'll hold off on accepting this as the answer in case anyone else can provide more insight/understanding, but I wanted to at least chime in saying that I had found a solution to my problem. I'm not sure what was happening before, but I could not find my session files anywhere sensible in the directories of my shared host user account and I'm wondering if they were there at all. It's also very strange to me that it worked for the support staff but not for me or a friend that I had test it on his own computer.
I have one user reporting that they are being logged out at 6:45 pm est (around that time). My session expire time is 24 hours and they login about 8 hours earlier.
Just as a test I set sess_time_to_update to PHP_INT_MAX as their is a known bug that causes session logouts when it is rotating the session.
The only thing I can think of that would cause this is Firefox's ability to restore previous tabs. This actually restores the session cookie even after the browser is closed.
She said this also happens in Internet Explorer...I couldn't find a setting in IE 11 to persist session cookies after the browser closes.
Do you have any ideas what could be causing this or an idea of what to investigate?
EDIT: This happened to another client. It happens only some days and doesn't happen to users at a different location. Is there anything I can do to determine how this is happening?
Try testing it in a few different browsers and see if it's still happening.
If it is, maybe:
Check if there are any cron jobs running server side that could be killing session cookies on the server?
Use a tool like IECookiesView to see what cookies are there, when they're set to expire and if anything is changing?
If they keep getting logged out at similar times try working out anything that might be happening server or local side at that time. It's unlikely a restore tabs (with cookies) feature could be randomly running at the same time.
I remember seeing a feature in Firefox to clear all cookies on exit as well, are they rebooting around that time?
Hope I helped.
I'm not sure that you're setting the actual expiration period of sessions to PHP_INT_MAX. As stated in the manual sess_time_to_update config controls how often the session class will regenerate itself and create a new session ID. In other words it's how often the session details (such as last activity) are getting updated, not expired.
On the other hand there are a few configuration directives that have influence on unexpected session expirations of your case:
sess_expiration: The number of seconds you would like the session to last. The default value is 2 hours (7200 seconds). If you would like a non-expiring session set the value to zero: 0.
sess_expire_on_close: Whether to cause the session to expire automatically when the browser window is closed.
Make sure that these settings are set fine and then try to reproduce the situation on your own browser to minify the scope of the problem. If you still experience random logouts add a log_message() call to session library's sess_destroy() to keep track of user session destruction that may give you a clue about the destruction pattern.
If nothing, I think that would be user's browser or CCleaner-like apps on her machine wiping off the cookie. Instruct her to factory reset her browser settings or install a brand new browser.
The other thing worth noting is that some CI libraries such as IonAuth has their own related configs. If you're using IonAuth for authentication please have a look at user_expire and remember_users directives in the ion_auth.php config file.
Hope it helps.
After one day of extensive research on the internet, I still can't figure out this one.
What is happening is that PHPSESSID in the cookie isn't persisting from one page to another.
This is happening in computers under one internet connection in a specific place. I've tested several others machines located elsewhere and everything works fine. I've checked session_start, there's no problem with subdomains.
I hope someone can help me out.
Things to check:
Is the time (and time zone!) set correctly on those computers? If it's set incorrectly, they may be discarding session cookies prematurely (possibly even immediately).
Is any odd security or "privacy" software installed on the computers? If possible, check if the issue persists under another browser on those machines.
Are these computers behind any sort of web proxy? If so, it may be meddling with cookies.
To use cookie-based sessions, session_start() must be called before
outputing anything to the browser. - PHP Documentation
Also you may want to check that your php.ini is configured properly to store your session cookies. Either that or call session_set_cookie_params() every time the page is loaded before the session is started in order to properly configure the session cookie's folder, domain, duration, etc.
Set cookie parameters defined in the php.ini file. The effect of this
function only lasts for the duration of the script. Thus, you need to
call session_set_cookie_params() for every request and before
session_start() is called.
This function updates the runtime ini values of the corresponding PHP
ini configuration keys which can be retrieved with the ini_get().
After I verified with my own computer that this was happening in this place, I realised that when I typed some URLs, they got somehow changed in the middle, for example http://www.medicmanager.com.ar/cloud/santiago/charisma/js/jquery.cookie.js was changed into http://www.medicmanager.com.ar/cloud/santiago/charisma/js/jquery.ckiooe.js, which of course gave 404.
I changed the ISP connection to another, and it started working, so I called the ISP and they told me they've been with this problem for 2 days, changing URLs and messing up with cookies.
Thank you all for your answers, and I leave this here in case someone is in doubt. Yes, it can be your ISP, very strange.
Setting the cookie lifetime to 0 means it will expire straight away, try setting it to another value e.g. 2592000 - which is 30 days in seconds.
EDIT: I meant time() + 2592000
Session ID is stored on the client in a way that usually dissipates when the browser is closed (stored as a cookie?).
Session ID and associated data is stored on the server (where?) for each client that starts one.
The main thing I wonder about is how the server knows when a session has ended, though. If the client no longer has the session ID stored (say, after closing their browser) and they try to ask the server for another session, it starts a new session. Does the server know to garbage collect the previous session data after some set amount of time? It seems to me like something that could be abused...
Session ID is usually stored on client browser using a cookie (alternatively, in URL parameters, but this is not recommended, as explained in http://php.net/manual/en/session.security.php)
Sessions are stored in the directory defined by session.save_path (e.g. /var/lib/php/sessions), or the system's temporary directory if this is not set (usually /tmp).
Sessions are garbage collected periodically, either by PHP itself during a request, or by a cron job (e.g. on Debian this is the default). See http://php.net/manual/en/session.configuration.php#ini.session.gc-probability
The main thing I wonder about is how the server knows when a session has ended
He doesn't know. However he knows when a session has not been used since a certain period of time, so it can delete unused sessions.
Does the server know to garbage collect the previous session data after some set amount of time?
Yes. This is defined by the session.gc_maxlifetime ini setting. Any session older than that will be deleted during a garbage collect. Garbage collect frequency can be tuned with the session.gc_probability and session.gc_divisor ini settings. (See doc.)
It seems to me like something that could be abused.
If you mean that someone may be able to create too many staled sessions on the server; yes this is probably true.
what you describe is perfectly right. And yes, it can be abused easily. There's even a tool out that automatically hijacks sessions around you (search for firesheep). The sessions are usually stored as either SESSION cookies or are passed between sever and client each time.
Check the PHP for a very brief intro, and some google on session and security will get you further.
Sessions expire automatically and are cleared up depending on the settings (after 20 days of no usage for example) and they are stored on linux, usually under /tmp/
Check php.ini for more information
I have read dozens of solutions to this and tried almost every one of them, but my sessions times out quickly anyway. I'm using a Debian installation and have set max variable in /usr/lib/php5/maxlifetime to 86400. I've also set session.gc_maxlifetime = 86400 in php.ini. I've made the session cookie valid for one hour and every time I reload the page I update it with another hour. I have tried setting ini_set("session.gc_maxlifetime", "86400"); in my front controller. However nothing helps. If I login to my site and wait about 20 minutes the next time I click a link on the page I will be logged out. The session cookie is still valid and the session file in /var/lib/php5 still exists. I just don't get it. I should also mention that I use Parallels PLESK on the system and it has made a lot of modifications to the standard Debian install, but I don't think that's the problem. Anyone?
It's entirely possible there's more than one .ini being loaded and where the one you made your session changes to is being overridden by one loaded later in the chain. Dump out a phpinfo() where your session validation/login code are and see what the session settings are. Part of the output will also be a list of the .ini files that were loaded.
Is it possible you have something a .htaccess conflicting with everything else? And are you sure you do not set this somewhere else in your code or some custom php.ini?
Everytime I have such problems I finally realise I forgot ONE place.
Does php -i | grep session.cookie_lifetime (at console) or phpinfo() (in script) verify your change to the cookie lifetime parameter?
If you use Firefox, try installing the Web Developer Toolbar and Firebug to inspect the cookies and network activity. This is a very useful combination for me when investigating issues where the hash value of a session cookie changes.
It's also possible that somewhere in your code or libraries you have a call to session_set_cookie_params() that's overloading your expected behavior. You can inspect cookies with either of the extensions above to verify their expiration.
I'm not sure if this will help, but make sure you're using both ob_start() & session_start();
ob_start();
session_start();
That's weird, a solution could be to implement a "Remember Me" feature with cookie. I know sessions can be very fickle, if you log-in on another comp, or the same comp but different browser, the cookie could be destroyed.
Also is the session really getting destroyed? Or is a new session being generated?