Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP sessions expiring early

Tags:

php

session

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).
like image 305
pwaring Avatar asked Sep 21 '11 08:09

pwaring


1 Answers

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.

like image 128
symcbean Avatar answered Oct 19 '22 13:10

symcbean