PHP session cookie refresh

This blog has moved to http://brian.moonspot.net/.

I have always had an issue with PHP Sessions. Albeit, a lot of my issues are now invalid. When they were first implemented, they had lots of issues. Then the $_SESSION variable came to exist and it was better. Then memcached came to exist and you could store sessions there. That was better. But, still, after all this time, there is one issue that still bugs me.

When you start a session, if the user had no cookie, they get a new session id and they get a cookie. You can configure that cookie to last for n seconds via php.ini or session_cookie_set_params(). But, and this is a HUGE but for me, that cookie will expire in n seconds no matter what. Let me explain further. For my needs, the cookie should expire in n seconds from last activity. So, each page load where sessions are used should reset the cookie’s expiration. This way, if a user leaves the site, they have n seconds to come back and still be logged in.

Consider an application that sets the cookie expiration to 5 minutes. The person clicks around on the site, gets a phone call that lasts 8 minutes and then gets back to using the site. Their session has expired!!!! How annoying is that? The only sites I know that do that are banks. They have good reason. I understand that.

My preference would be to either set an ini value that tells PHP sessions to keep the session active as long as the user is using the site. Or give me access to the internal function php_session_send_cookie(). That is the C function that sends the cookie to the user’s browser. Hmm, perhaps a patch is in my future.

In the short term, this is what I do:

setcookie(
ini_get("session.name"),
session_id(),
time()+ini_get("session.cookie_lifetime"),
ini_get("session.cookie_path"),
ini_get("session.cookie_domain"),
ini_get("session.cookie_secure"),
ini_get("session.cookie_httponly")
);

That will set the session cookie with a fresh ttl.

Ok, going to dig into some C code now and see if I can make a patch for this.

About these ads

21 Responses to PHP session cookie refresh

  1. […] Moon posted new article how to deal with session cookies. Sometimes there is problems with session cookie refresh. Brian […]

  2. Dan Caragea says:

    For this reason I created a keepalive js function which preloads a “image” every few minutes. Something like this:
    tempImage.src=baseurl+”/ajax/keepalive.php?”+cur_time;
    The php script simply calls session_start() so the session is refreshed for as long as one page of my site is opened in the browser. This is good for as long as people are not using public computers.

  3. Jani says:

    Perhaps I missed some point here, but why don’t you simply leave the lifetime to 0 which makes the cookie a “session” cookie which expires when browser is closed? (that’s the default btw..)

  4. My recommendation is to just set the timeout big enough and to consider a session to be “idle” after a while of inactivity.

    In my opinion, setting a new cookie in every response is not wise.

  5. […] Moon has posted a tip (and a bit of code) he’s worked up to help make a users cookies last a bit longer than they […]

  6. Chris Barber says:

    I agree with Jani. Just have the session cookie expire when the browser is closed and have the session expire on the server (thus invalidating the cookie) after 20 minutes (or however long). On the server side, the session is ticked and kept alive for X minutes after the last activity. With an Ajax call, you can write a keepalive to tick the session. The only reason I see to set the session cookie’s expire time is to preserve the session between browser sessions. If you are building a secure app, session cookies should expire when the browser closes, effectively logging the user out.

  7. Brian Moon says:

    I guess I should have been clearer about my usage in my post. In our application, we keep two cookies. One that is set for 30 days. This keeps you logged in for preferences, display options, etc. Think iGoogle or My Yahoo!

    We keep a second cookie that must be set to allow a person to change anything about their account. This second cookie is more like what you are talking about. Again, see Yahoo!’s system for managing user account information.

    So, to do both of these things, I would have to write my own “session” code to keep a person logged in for preferences and such over a longer period of time and then use PHP sessions for the short term stuff? That seems like a huge waste IMO.

    As for “secure applictions” why does PHP even allow you to set the expiration time if it is so unsecure? Perhaps there should be a patch to remove that. =P

  8. Malicious users can still change the expiration date of your login cookie (there’s a simple extension for the in Firefox), which would cancel out this security precaution because it’s meant to protect against “hackers” most of which are aware of ways to edit cookie data.

    Instead of relying on 2 separate cookies, set a single cookie that has 2 values:
    1) A cookie token (SHA-1 hash of some data from the users account)
    2) An additional random 8-10 character string.

    When this cookie is created, it should be saved in the database. Call the table “user_passports”.

    This table has the following fields:
    user_id
    token
    keycode
    expires
    last_used
    created

    Whenever the cookie is first created (example: the user logs in), a new row should be added to the “user_passports” table. The “token” field is the SHA-1 token and the “keycode” field is the 8-10 character random string. These 2 fields must be completely unique for any row in the database.

    The cookie will be used as a last resort to log the user in. It would look something like this:

    IF THE SESSION EXISTS
    Validate the session.
    If session is valid, user is valid.
    If session is not valid, continue down the list.
    ELSE IF THE COOKIE EXISTS
    Validate the cookie.
    If the cookie is valid, user is valid.
    If the cookie is invalid, continue down the list.
    ELSE
    User is not logged in.

    I like to store my sessions in the database. In the sessions table I have the usual fields like session variables, last updated, created etc. I add another field to the sessions table called user_id. This way the user id is not stored as session data but is related to the session via the database.

    This way when the page reloads and I make sure the PHP session is valid (using my Session class and session_set_save_handler()), all I have to do is pull out the user_id and I know the user is logged in and who they are.

    If the session has expired (my setting is 45 minutes), all I have to do is revert back to the cookie.

    So to achieve exactly what you want to do, all I would have to do is make these changes to my user validation class:

    1) If a cookie is used to validate the user (and is successful), I’ll need to do a SELECT in the database anyway to make sure the cookie is valid. In this SELECT, I’ll retrieve the last_used timestamp. If the timestamp is older than X amount of time, I’ll ask the user to enter their password before editing any sensitive data.

    2) This will be the only real overhead. If the cookie is set, I’ll need to do a single UPDATE query to update the last_used time in the Passports table *every time the user loads the page*

    Of course the method I listed above uses my validation scheme by adding additional cookie security by referencing the cookie to an actual row in the database (the “user_passports” table). I believe this the most secure form of persistent validation because I can at any point purge all rows from the user_passports table which will invalidate all cookies. It also gives me some basic statistics about who’s using cookies and helps with raising red flags for malicious users (ie: user_id 33 has 370 cookie entries? that can’t be right…).

  9. Apologies for any typos and such as it’s very late where I am :)

  10. Brian Moon says:

    @Artem I would never EVER simply check for the existence of a cookie. That would be insane, wreckless and stupid. Of course it must validate to something on the backend.

  11. Then since the cookie is unique to that specific user, you can simply use the last_used field to make the check.

    This way you can set the cookie to expire 1 year from now and the actual check to update secure account data is done with the help of the database and the last_used field.

  12. > memcached came to exist and you could store sessions there

    How does this compare to using /dev/shm as the store for session data?

  13. Brian Moon says:

    When you have 10 servers, /dev/shm is not as nice. It is much simpler to use memcached as you don’t have to worry about sticking a person to one server. With memcached and highly optimized mysql data, our web servers can be comletely stateless.

  14. […] session cookie refresh – Brian Moon juin.08, 2008 in Actualités via Planet PHP par (author […]

  15. > When you have 10 servers…

    What about if you just have one?

  16. Brian Moon says:

    Yes, well, if you just have one, then shared memory or things like APC and xcache are going to be way better than memcached. I always advocate those for single server use. It just so happens however, that by the time PHP go sessions, dealnews had more than one server. And when designing Phorum, I try and take that into account as well since it was originally designed and created for dealnews.

  17. Juan S says:

    We might be using this on our website :)

  18. djonline says:

    Brian Moon, but when 1 memcached server is down, and memcached is not have fault tolerance and replication yet, you lose stored session data ?!

  19. Brian Moon says:

    @djonline yes. But you should never store anything in memcached that you can not lose. It is a cache, not storage. We never store anything in sessions that is not in a table somewhere. To do so would be horrible. The session is just there so we don’t need to load the data every time for that user.

  20. jayu says:

    Hello

    In one of my project If user forgot to log out and closed the browser. At that time how I manage the database with automatically log off in php mysql

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: