Welcome Guest, Not a member yet? Register   Sign In
Solution to session data loss when using AJAX
#1

[eluser]intractve[/eluser]
Hi All,
This post is a compilation of the steps taken to fix the issue of session updates (using the in-built CI_Session library) while using AJAX in your pages.
(This post assumes you are using the CI session with a database and not just cookies. This solution may work for just cookies too, I am not sure though.)

The CI Session library automatically updates the session information i.e changes the session_id (by default) every 5 mins
(configurable via config.php -> $config['sess_time_to_update']).
While this is a very useful security feature to thwart session hijacking, it can prove to be a bone when using AJAX.

When static pages are accessed, the CI session update does not interfere with regular operation and the new session id is updated in the cookie set in your system, and all is well. But when an AJAX operation is done (get or post), the session is updated and a new session id is generated (and updated in the database) but the cookie in the browser is not updated, so the next time the browser requests a new page it sends a cookie with the wrong session id and the session becomes invalid resulting in loss of session data (person getting kicked out if logged in).

I do not take credit for any of the solutions below, I'm just putting it in one place so that people do not waste as much time as I did trying to solve this. I have given due credit to the posters of the solution but if I have gotten it wrong or not credited you please let me know and I will update the post.

Step 1:
In constants.php (application/config/) you have to add the following line to define an AJAX request.
Taken from WebLee (http://www.weblee.co.uk)
Code:
// Define Ajax Request
define('IS_AJAX', isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');
//

Step 2:
Create a new file under (application/libraries) called MY_Session.php
The word MY_ should correspond to whatever you have defined in config.php as your prefix for class extension ($config['subclass_prefix'])
Paste the following into that file.
Solution by WanWizard
Code:
<?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();
       }
    }

}

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

And that's it!


What we have done is extended the Session Library overriding the update_session function which is responsible for creating new Session ID's and telling it to only update the session if the current call is not AJAX.

I have tested this and it works,

If there are any errors or better solutions feel free to post them below, so all can benefit from it.


Merry Christmas and Happy Holidays everybody...
:-)

--
George
#2

[eluser]n0xie[/eluser]
Very informative.

Thanks you for the clean solution!
#3

[eluser]Colin Williams[/eluser]
Good stuff, George. Thanks
#4

[eluser]renownedmedia[/eluser]
It worked like a charm, thanks!
#5

[eluser]Unknown[/eluser]
Thxs! Exactly what I was looking for!
#6

[eluser]adamk[/eluser]
I wish I had found this thread two days ago!!
#7

[eluser]slowgary[/eluser]
Hi guys,

This is a great thread and has helped me identify the bug I've been chasing. I did some testing, however, and confirmed that upon return of an ajax call, the browser DOES INDEED get the returned cookie.

Then it occurred to me that the problem could be caused by echo()'ing the JSON data directly, since it's likely that the output is sent before the cookie header... but in my application, I'm using a view to send JSON results.

I'm indeed experiencing the problem, as my application will just randomly invalidate my session and it's definitely during an AJAX call (my login box comes back as the returned AJAX data).

Can anyone shed more light to the cause of this problem? I've found other threads referencing this as well but none seem to conclude anything definitive.

Thanks!
#8

[eluser]WanWizard[/eluser]
Check the value of the cookie sent to the server by the browser when this happens. Is it the same as the one originally received by the page, or is it the last one received via the ajax call?
#9

[eluser]slowgary[/eluser]
I stumbled on this thread after the last instance of the issue, so I haven't been able to do that yet, but I will. During my testing, I setup a simple static page with an AJAX call to a server-side script. In the server-side script I set a cookie. Upon visiting the static page for the first time, the AJAX call fires and the cookie gets set.

I'm convinced this problem is AJAX related, and it's sporadic enough that it definitely seems to be also related to the 5 minute session id regeneration. If AJAX calls do set cookies though, what causes the actual problem?
#10

[eluser]slowgary[/eluser]
I think I understand the issue, will anyone confirm? It's more of a race condition than anything, but it just so happens that the conditions are more likely repeated for applications that have many concurrent AJAX calls, which mine does.

Anytime two requests are returned in a different order than they are sent, your application has the potential of destroying the session (if the regeneration happens after the first request). Since AJAX is asynchronous, there are plenty of opportunities for this to happen. In my application, I'm making two AJAX requests at the same time, one of which usually takes longer since it returns more data.

The proposed solution above will decrease the likelihood of this problem occurring for AJAX heavy applications, but in applications that serve assets this could also creep up. It seems that CodeIgniter's Session library is not suitable for applications that require concurrent requests from a single user. This is unfortunate.




Theme © iAndrew 2016 - Forum software by © MyBB