EllisLab text mark
Advanced Search
1 of 2
1
   
UNRESOLVED - The only REAL problem with CI Sessions: Please confirm this Bug
Posted: 12 October 2010 04:20 PM
Avatar
Joined: 2009-03-21
680 posts

EDIT - Will someone from EllisLab confirm this bug?  Is this resolved in CI2.0?  Thanks.

Hi all,

I’ve read many posts about the session class being faulty and I have to say that for the most part, they’re wrong.  I do, however, believe there is a real problem with CI Sessions.  In a regular, old school web-app you may never see this scenario.  These days this is a more common scenario and one that I am currently facing.

Here it is:

“Bob” has been staring at a web application for 6 minutes, which means his very next request will get a new session ID.  He clicks a button that initiates TWO ajax requests.  The first request hits the server side which runs through the session ID regeneration.  The second request which has already left the client with the old session ID, hits the server and causes Bob’s session to be destroyed.

And there it is.  This problem is not limited to AJAX requests, but any concurrent requests.  The most likely examples I could think of are AJAX heavy applications and serving assets through a controller.  I’ve seen a few proposed solutions which disable the sess_update() call for AJAX requests, but as mentioned this problem is not restricted to AJAX.


If you can add any additional info, or prove that this is incorrect or that some config change will solve the issue, please let me know.

Thanks for reading.

 
Posted: 12 October 2010 05:16 PM   [ # 1 ]   [ Rating: 0 ]
Avatar
Joined: 2009-02-19
4325 posts

To me, it looks like the ajax request WAS the problem in your scenario, but you say it isn’t limited to ajax.  Had the sess_update() request been ignored on that ajax request, I don’t think there wouldn’t have been a problem.

Another thing that can help is to not send out more than one ajax request until you receive the first response back.  Like using an autocompleter is murder on native CI sessions (where it is sending an ajax request for every keypress…which can be a lot…and close together if you type fast).

I have not had any problems with CI Sessions once I changed the sess_update() to ignore requests made with Ajax.

Its really easy to fix.
1) in application/config/constants.php add:

define('IS_AJAX', isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest'); 

2) in application/libraries, create MY_Session.php and override the sess_update() method.

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class 
MY_Session extends CI_Session 
{

/**
* Update an existing session
*
* @access    public
* @return    void
*/
    
function sess_update()
    
{
       
// skip the session update if this is an AJAX call!
       
if ( !IS_AJAX )
       
{
           parent
::sess_update();
       
}
    } 
 Signature 
 
Posted: 12 October 2010 05:51 PM   [ # 2 ]   [ Rating: 0 ]
Avatar
Joined: 2009-03-21
680 posts

CroNiX,

Thanks for your reply.  I have seen this proposed solution, but it is inadequate.  AJAX requests transport cookies both ways between client and server, and thus are not truly any different than any other request.  The reason that they SEEM to be the problem is that they are commonly issued concurrently.

Indeed, ANY CONCURRENT REQUESTS are capable of creating this scenario.  If you read it carefully, you’ll see that it has nothing to do with the type of request, but is caused by the fact that the first request causes the session ID regeneration while the second has already left the client with the old session ID.

This problem could just as easily plague an application that serves images via a controller, since the client will request those images concurrently.

 
Posted: 12 October 2010 05:56 PM   [ # 3 ]   [ Rating: 0 ]
Avatar
Joined: 2009-03-21
680 posts

As terrible a solution as it may be, I’m considering just overriding the sessions library and disabling the sess_update() function.  I’m less concerned about session fixation than I am about the application seeming very broken to its users.

 
Posted: 12 October 2010 06:09 PM   [ # 4 ]   [ Rating: 0 ]
Avatar
Joined: 2009-12-08
1804 posts

Why not just increase $config[‘sess_time_to_update’]?

 Signature 

@basdflasjk | BitAuth: Authentication and Role-based Permissions | Session Library Replacement


Please read the User Guide! (Upgrading from a previous version?)

 
Posted: 12 October 2010 06:38 PM   [ # 5 ]   [ Rating: 0 ]
Avatar
Joined: 2009-03-21
680 posts

That doesn’t solve the problem.  It would increase the amount of time between regenerating a user’s session ID, but once that time has passed the bug will still present itself.

 
Posted: 08 November 2010 06:36 AM   [ # 6 ]   [ Rating: 0 ]
Avatar
Joined: 2009-05-05
241 posts

lol - I just realised I’ve got the same problem as you, and I’ve arrived at the same conclusion.

Check out my post here: http://ellislab.com/forums/viewthread/90901/P15/

 
Posted: 08 November 2010 07:15 AM   [ # 7 ]   [ Rating: 0 ]
Avatar
Joined: 2009-06-19
6583 posts

This works!

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

/**
 * ------------------------------------------------------------------------
 * CI Session Class Extension.
 * ------------------------------------------------------------------------
 *
 * Add the following define to the bottom of application/config/constants.php
 * // Define Ajax Request
 * define('IS_AJAX', isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');
 *
 */

class MY_Session extends CI_Session {
   
/*
    * Do not update an existing session on ajax calls
    *
    * @access    public
    * @return    void
    */
    
public function sess_update()
    
{
        
// if not an AJAX call update the session
        
if ( ! IS_AJAX)
        
{
            parent
::sess_update();
        
}
    }

    
function sess_destroy()
    
{
        parent
::sess_destroy();

        
$this->userdata = array();
    
}
}

// ------------------------------------------------------------------------
/* End of file MY_Session.php */
/* Location: ./application/libraries/MY_Session.php */ 

InsiteFX

 Signature 

Certified State of CT Computer Programming Teacher.
Custom Designed Icons, eBook Covers Software Boxes. CD, DVD Etc. New iPhone® Tab Bar Icons and iPhone® Applications Icons.

Skype: insitfx

STOP! Before posting your questions, remember the WWW Golden rule:
What did you try? What did you get? What did you expect to get?

Input -> Controller | Processing -> Model | Output -> View

 
Posted: 08 November 2010 07:58 AM   [ # 8 ]   [ Rating: 0 ]
Avatar
Joined: 2009-05-05
241 posts

Hi InsiteFX - unfortunately this code does NOT solve the problem. It is not AJAX requests. And I just tested it on a fresh CI install with your code - the bug still occurs.

You can see how I replicate the error from scratch here: http://ellislab.com/forums/viewreply/821371/

If you follow those steps, then try your code, you’ll see the error still occurs (you basically mash F5 on my code and it’ll occur).

 
Posted: 08 November 2010 11:52 AM   [ # 9 ]   [ Rating: 0 ]
Avatar
Joined: 2009-03-21
680 posts

If you read the scenario in my first post, you’ll see that this problem can happen anytime there are concurrent requests, it has NOTHING to do with AJAX.

I’m a little disappointed that we haven’t seen an official reply from EllisLab.  Does anyone know if CI2.0 is still plagued with this bug?

Thanks.

 
Posted: 08 November 2010 05:58 PM   [ # 10 ]   [ Rating: 0 ]
Avatar
Joined: 2008-11-04
4489 posts

This bug still exists in CI 2.0.

I’ve written a post on this subject a few months ago. Fixing this means modifying half the session library code. I had a first version online, but wasn’t happy with it. I’m currently cooking a new version.

What basically has to happen is when the session ID rotates, the old session ID has to be kept in the cookie. You then query the session table with (id = old_id OR id = new_id). If a record is found and the session id == old_id, update the cookie so it’s ok again. This works as long as no requests lasts longer than the sess_time_to_update (otherwise you might have two rotations, and you still loose the session).

 Signature 

Me: WanWizard.eu | My company: Exite | Datamapper: DataMapper ORM <= LOOKING FOR A NEW MAINTAINER!

 
Posted: 08 November 2010 06:22 PM   [ # 11 ]   [ Rating: 0 ]
Avatar
Joined: 2008-11-04
4489 posts

For those who can’t wait, the previous version of my session library.

Note that this one stores the previous session_id in the database (the bit I’m not happy with). It contains several other changes as well, so read the header carefully before using this version.

 Signature 

Me: WanWizard.eu | My company: Exite | Datamapper: DataMapper ORM <= LOOKING FOR A NEW MAINTAINER!

 
Posted: 10 November 2010 10:23 AM   [ # 12 ]   [ Rating: 0 ]
Avatar
Joined: 2009-05-05
241 posts
WanWizard - 08 November 2010 11:22 PM

For those who can’t wait, the previous version of my session library.

Note that this one stores the previous session_id in the database (the bit I’m not happy with). It contains several other changes as well, so read the header carefully before using this version.

Thanks for this Wan!!!!! This is awesome.

FYI - If there is a triple request it is still possible to kill the session (I was able to do it in my tests) - but I guess thats going to be pretty rare (to firstly get a triple request, and for it to occur at the ‘300’ sec mark when the session is changed).

Question - why did you change the cookie only write itself when explicitly forced to? If I wanted to revert this to the original (so it is instantly compatible with my current code) - I just need to remove lines 279-282?

Thanks again. Hopefully Ellis Labs looks into this a bit more….

 
Posted: 10 November 2010 01:35 PM   [ # 13 ]   [ Rating: 0 ]
Avatar
Joined: 2008-11-04
4489 posts

That’s why I said the entire session class should be rewritten.

Session ID rotation happens based on information in the cookie. In case of multiple concurrent requests, the original cookie is send. If the first request decides it’s time to rotate the ID, so will the second (as it’s using the last used date in the cookie, instead of the one from the database, which could have been updated in the meantime.

By default, the session library does an UPDATE for every modification to the session variables. It also writes a Set-Cookie to the HTTP header. If you, like me, uses session variables a lot, you will end up with dozens of queries, and a HTTP header which can easily exceed the page in size. Which will have quite a significant performance impact.

To revert my fix, simply change the default value of the write() parameter from FALSE to TRUE.

 Signature 

Me: WanWizard.eu | My company: Exite | Datamapper: DataMapper ORM <= LOOKING FOR A NEW MAINTAINER!

 
Posted: 11 November 2010 06:05 AM   [ # 14 ]   [ Rating: 0 ]
Avatar
Joined: 2009-05-05
241 posts

Ok cool… I ‘get’ what you are saying, but what I’m not sure is where do you force the session update in your code to ensure it is done correctly? i.e. where do I call it from?

 
Posted: 11 November 2010 08:10 AM   [ # 15 ]   [ Rating: 0 ]
Avatar
Joined: 2008-11-04
4489 posts

My applications are completely modular.

The application/controllers folder only contains a single bootstrap controller that processes the URI, fetches theme and template information, fetches page layout information, calls module controllers to generate the sections in the template, and displays the page. And after that the session is updated.

The bootstrap is always called, regardless of the URI.

 Signature 

Me: WanWizard.eu | My company: Exite | Datamapper: DataMapper ORM <= LOOKING FOR A NEW MAINTAINER!

 
1 of 2
1