Home » Php » security – Session timeouts in PHP: best practices

security – Session timeouts in PHP: best practices

Posted by: admin April 23, 2020 Leave a comment

Questions:

What is the actual difference between session.gc_maxlifetime and session_cache_expire() ?

Suppose I want the users session to be invalid after 15 minutes of non-activity (and not 15 after it was first opened). Which one of these will help me there?

I also know I can do session_set_cookie_params() which can set the user’s cookie to expire in some amount of time. However, the cookie expiring and the actual session expiring on the server side are not the same; does this also delete the session when the cookie has expired?

Another solution I have though of is simple
$_SESSION['last_time'] = time()
on every request, and comparing the session to the current time, deleting the session based on that. I was hoping there was a more “built-in” mechanism for handling this though.

Thanks.

How to&Answers:

Each time session_start is called the session files timestamp (if it exists) gets updated, which is used to calculated if session.gc_maxlifetime has been exceeded.

More importantly you can’t depend on a session to expire after session.gc_maxlifetime time has been exceeded.

PHP runs garbage collection on expired sessions after the current session is loaded and by using session.gc_probability and session.gc_divisor it calculates the probability that garbage collection will run. By default its a 1% probability.

If you have a low number of visitors there is a probability that an inactive user could access a session that should have expired and been deleted. If this is important to you will need to store a timestamp in the session and calculate how log a user has been inactive.

This example replaces session_start and enforces a timeout:

function my_session_start($timeout = 1440) {
    ini_set('session.gc_maxlifetime', $timeout);
    session_start();

    if (isset($_SESSION['timeout_idle']) && $_SESSION['timeout_idle'] < time()) {
        session_destroy();
        session_start();
        session_regenerate_id();
        $_SESSION = array();
    }

    $_SESSION['timeout_idle'] = time() + $timeout;
}

Answer:

I spent some time looking for a good answer to how the php.ini server settings make
sessions expire. I found a lot of info but it took a while to figure out why
the settings work the way they do. If you’re like me, this might be helpful to you:

Sessions are stored as cookies (files on the client’s pc) or server side as files
on the server. Both methods have advantages and disadvantages.

For the sessions stored on the server, three variables are used.

session.gc_probability
session.gc_divisor
session.gc_maxlifetime

(session.gc_probability/session.gc_divisor) produces the probability that the
garbage collection routine will run. When the garbage collector runs, it
checks for session files that haven’t been accessed for at least session.gc_maxlifetime
and deletes them.

This is all explained pretty well in forum posts (this one especially!) – But the
following questions do come up:

1.) How is that probability applied? When does the server roll the dice?

A: The server rolls the dice every time session_start() is called during
any active session on the server. So this means you should see the garbage
collector run roughly once for every 100 times that session_start() is called
if you have the default of session.gc_probability = 1 and session.gc_divisor = 100

2.) What happens on low volume servers?

A: When session_start() is called it FIRST refreshes the session and makes the
session values available to you. This updates the time on your session file on the
server. It THEN rolls the dice and if it wins (1 out of 100 chance) it calls the garbage collector. The garbage collector then checks all session id files and sees if there are
any that are eligible for deletion.

So this means that if you are the only person on the server, your session will
never go inactive and it will appear as though changing the settings have no
effect. Let’s say you change session.gc_maxlifetime to 10 and session.gc_probability
to 100. This means there is a 100% chance the garbage collector will run and it
will clear out any session files that haven’t been accessed in the last 10 seconds.

If you’re the only one on the server, your session will not be deleted. You need
at least 1 other active session running for yours to go inactive.

So basically, on a low volume server or at a low volume time – it could be MUCH
longer than session.gc_maxlifetime before the garbage collector actually runs and
the sessions are actually deleted. And without knowing how this works, it may
appear completely random to you.

3.) Why do they use the probability?

A: Performance. On a higher volume server you don’t want the garbage collector
running on every request of session_start(). It will slow down the server
needlessly. So depending on your server volume, you may want to increase
or decrease the probability that the garbage collector runs.

I hope that this ties things together for you. If you’re like me and you tried
session.gc_maxlifetime and it didn’t seem to work (because you tried it
out on a development server so as not to disturb anyone), then this post
hopefully saved you some head scratching.

Good luck!

Answer:

session.gc_maxlifetime is based off of the last time a session file was modified. So every time a session file is modified or a session_start() is called in a separate page, the countdown to gc_maxlifetime begins anew and the user stays “logged in”. This is the value you are looking for. You can modify this through ini_set() in your php files, or edit php.ini if you have access to it

session_cache_expire() only controls the HTTP “Expires” header. This header controls how long the downloaded page contents stay in the user’s browser cache.

Answer:

To check the current values, this code will be helpful:

$gc_maxlifetime = ini_get('session.gc_maxlifetime');
$gc_probability = ini_get('session.gc_probability');
$gc_divisor     = ini_get('session.gc_divisor');