persisted login with Zend_Session::rememberMe

2019-02-04 22:58发布

问题:

I'm using Zend_Session to manage my user sessions, and I was looking to implement a "Remember Me" option in my application to keep users logged in for 2 weeks or so.

I've noticed that Zend_Session already has a built-in function called Zend_Session::rememberMe, however I'm not sure if that function logic is correct to use as a persisted login.

Essentially, the rememberMe function just extend the active session expiration date, which means if the user use the remember me option, he'll stayed logged in for 2 weeks with an active session.

This brings up 2 major issues.

  1. I'm storing the sessions on the database, which means all these inactive users are stored for 2 weeks in my session table. I have over 50k inactive sessions, and it's hurting the application performance.
  2. I want to know if a user came back to the site after 24 hours of inactivity, and revalidate his information. As his session remains open, I can't really tell if he came back after 1 hour or 1 week, as he has the same active session id.

I've read that if I want to implement a remember me feature, I shouldn't use the session cookie for that, and I should create another "login cookie" to remember a hashed user_id and a token. here's the complete explanation: What is the best way to implement "remember me" for a website?

So why does zend framework offers such a function, if using it can create performance and security issues?

回答1:

+1 for noting the major flaw behind Zend's approach to the 'remember me' functionality. Some people don't understand there is a penalty to be had when they attempt to extend the session lifetime, regardless of the session handler being file or db based. Allowing stale sessions to persist beyond a reasonable time-frame is a weak solution and you are better off implementing a custom cookie solution outlined by the link you provided.

The direct answer to your question; who knows. Maybe they didn't consider the fact that many users opt for database session handling, and figured piling up stale session cookies on the filesystem had no direct impact on performance.

Also, if you wanted to track if a user came back and re-established a stale session, you could add a 'updated_at' column to your session tracking table. So then you would have two timestamp columns; created_at and updated_at, which would help you make this determination.



回答2:

One can only speculate their reasons for offering the function, but I don't see any major reasons against having it either. Plenty of programming languages give you facilities to do something bad or write code that has unseen negative side effects.

Sure, there can be unforeseen implications if someone arbitrarily sets it to a very large value, but the thing to note is that session data is still subject to garbage collection based on session.gc_maxlifetime regardless of the rememberMe time set on a cookie. Calling Zend_Session::rememberMe() has no effect on garbage collection for that data.

Consider the following:

Bootstrap.php

protected function __initSession() {
    ini_set('session.gc_maxlifetime', 45);  // set session max lifetime to 45 seconds
    ini_set('session.gc_divisor', 1);       // 100% chance of running GC
    Zend_Session::start();
}

IndexController.php

public function indexAction() {
    $data = new Zend_Session_Namespace('data');

    if (!isset($data->time)) {
        // no active session - set cookie lifetime and set some data
        Zend_Session::rememberMe(90*86400);  // 90 days
        $data->time = time();
        echo "Setting time";
    } else {
        echo date('r', $data->time);
    }
}

If you were to access IndexController, the first time you would see Setting time. Then if you were to wait over 45 seconds, you would see the time printed out and (in my case) on the next request the session is expired. The session data is deleted from the server and although I still have the previous cookie, it is no longer recognized by the server.

I would expect that if you were implementing the garbage collection callback in your session save handler, then you should still see old session data removed from your database depending on what your gc_maxlifetime is set to.

To speak to your 2 questions:

As for your first issue, I would question why having 50,000 inactive sessions is hurting performance. If the database is properly indexed on the session ID, it should be extremely fast to get the session data even if there were millions of sessions in the database. Have you hit a hardware limitation possibly? Selecting data from 50,000 records when done properly should have little overhead.

In regards to your second issue, I agree with Mike, you should store a session value indicating when the last visit was, this way, when you start the session you can check their last visit and see how long it has been since their last page view. Then based on your threshold you can determine if they are returning to your site after being inactive.

For security reasons, if you detect it has been so long since their last visit, this is a good time to re-call rememberMe(), as doing so will issue a new cookie and help prevent session hijacking and fixation.