Welcome Guest, Not a member yet? Register   Sign In
Session Failures
#1

[eluser]Ian Cook[/eluser]
Under what circumstances could a session appear to mysteriously expire, or in some other way fail to reload between page views?

I have this intermittent problem where, between page views, the user session will get dropped. Before I implemented auth checking code, the page would load but anything requiring data from the session would fail to load that data. After I implemented auth checking, it would just kick the user back to the login page ( as would be expected due to missing or expired session data ).

I've tested 5 minute and 10 minute time spans to see if the timeout is occurring too early, but neither of those times cause the issue to happen. And in any case, I've seen the session drop after only a few seconds.

I've clicked between every page of the site ( there are only 6 pages ) to see if it was a certain page causing it to drop. No dice.

Sessions work perfectly, other than this intermittent and unreproducible error.

I'm encrypting the session cookie. I'm storing userdata in a database table. The session is set to expire after 7200 seconds. I'm setting the cookie for my domain properly.

Here is my session config from config/config.php

Code:
/*
|--------------------------------------------------------------------------
| Session Variables
|--------------------------------------------------------------------------
*/
$config['sess_cookie_name']        = 'ci_session';
$config['sess_expiration']        = 7200;
$config['sess_encrypt_cookie']    = true;
$config['sess_use_database']    = true;
$config['sess_table_name']        = 'ci_sessions';
$config['sess_match_ip']        = FALSE;
$config['sess_match_useragent']    = TRUE;
$config['sess_time_to_update']     = 300;

/*
|--------------------------------------------------------------------------
| Cookie Related Variables
|--------------------------------------------------------------------------
*/
$config['cookie_prefix']    = "";
$config['cookie_domain']    = "secure.example.com"; # i only want the cookie accessible from this exact domain
$config['cookie_path']        = "/";

I'm mostly trying to find out under what scenarios a session COULD fail.
#2

[eluser]tomcode[/eluser]
Hi thinkspill,

Have You tried without use of database ?
I'd try that to reduce possible error sources.

Have You tried without session encryption ?
I've had once the case where a server would not accept encrypted sessions, while uncrypted did pass. I got error messages, though, which leads me to :

Have You error messages enabled ?

Edit : Have You tried without user agent matching ?
#3

[eluser]Ian Cook[/eluser]
I have not tried without database session userdata storage, or encryption, or user-agent matching. I'll give it a shot.

I do have error messages enabled (E_ALL), but there are no errors.
#4

[eluser]Popcorn[/eluser]
What browser are you using?

Try removing the underscore from the cookie name.
#5

[eluser]Ian Cook[/eluser]
Oooookay, I've got a little more concrete information now.

So it appears that when the session ID regeneration occurs, the userdata that is stored in the database table is dumped into the cookie. If this userdata is greater than 4k, the cookie no longer works ( as expected, cookies cant handle that much data ).

I tested this by doing the following...

First I changed the session id regen time to 20 seconds, for faster testing.

Then I set an additional cookie that just contained the session id. On each page load I'd compare that session id to the real session id to determine if it had changed.

If it has changed, its either because the sessiond id has been regenerated or the session has been lost entirely. So I check if my "is auth'd" variable is still present. If so, then I'll update the session id cookie copy with the new one and continue on.

If the "is auth'd" variable is not set, and the session id copy does not match the real curent session id, the session has been lost.

I filled the session userdata up with a ton of junk data. If the userdata totals less than ~4k when the session regen occurs, the session remains intact. If the userdata totals more than ~4k, the session dies after the regen occurs.

So, in summary, the session library seems to be putting a copy of all the userdata into the cookie when it regenerates the session id.

This is a bug, right?
#6

[eluser]newsun[/eluser]
Ok,

So the problem here is with the Session.php library currently in SVN. There was a change which made where the userdata saves to the db and the identifying data saves to the cookie as well as the db, if saving to a db was setup and enabled.

The issue thinkspill was having was on the regeneration of the session id the userdata was getting put into the cookie, instead of the db. Below is the function with the problem. I broke each change out into code snippets:

Code:
function sess_update()
    {
        // We only update the session every five minutes by default
        if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now)
        {
            return;
        }
    
        // Save the old session id so we know which record to
        // update in the database if we need it
        $old_sessid = $this->userdata['session_id'];
        $new_sessid = '';
        while (strlen($new_sessid) < 32)
        {
            $new_sessid .= mt_rand(0, mt_getrandmax());
        }
        
        // To make the session ID even more secure we'll combine it with the user's IP
        $new_sessid .= $this->CI->input->ip_address();
        
        // Turn it into a hash
        $new_sessid = md5(uniqid($new_sessid, TRUE));
        
        // Update the session data in the session data array
        $this->userdata['session_id'] = $new_sessid;
        $this->userdata['last_activity'] = $this->now;
Change:
Code:
#Set the cookie data to default
        $cookie_data = null;

Code:
// Update the session ID and last_activity field in the DB if needed
        if ($this->sess_use_database === TRUE)
        {
Change:
Code:
#Sets cookie data to omit the custom userdata
            $cookie_data = array();
            foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
            {
                $cookie_data[$val] = $this->userdata[$val];
            }
Code:
$this->CI->db->query($this->CI->db->update_string($this->sess_table_name, array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid)));
        }

Also, there was some optimizing that I did to the sess_write() function as well, eliminating a redundant loop:

Code:
function sess_write()
    {
        // Are we saving custom data to the DB?  If not, all we do is update the cookie
        if ($this->sess_use_database === FALSE)
        {
            $this->_set_cookie();
            return;
        }

        // We need two copies of the session data array.  One will contain any custom data
        // that might have been set.  The other will contain the data that will be saved to the cookie[code]
[b]Change:[/b]
        [code]#$cookie_userdata = $this->userdata; #removed as this can be accomplished later
Code:
$custom_userdata = $this->userdata;

        // Before continuing, we need to determine if there is any custom data to deal with.
        // Let's determine this by removing the default indexes to see if there's anything left in the array
Change:
Code:
# assigning the cookie data here as well so it does not have to be removed as previous code
Code:
foreach (array('session_id','ip_address','user_agent','last_activity') as $val)
        {
Change:
Code:
$cookie_userdata[$val] = $this->userdata[$val];
Code:
unset($custom_userdata[$val]);
        }
        
        // Did we find any custom data?  If not, we turn the empty array into a string
        // since there's no reason to serialize and store an empty array in the DB
        if (count($custom_userdata) === 0)
        {
            $custom_userdata = '';
        }
        else
        {
            // Before we serialize the custom data array, let's remove that data from the
            // main session array since we do not want to save that info to the cookie
Change:
Code:
/*foreach (array_keys($custom_userdata) as $val) #removed as this can be accomplished earlier with less code
            {
                unset($cookie_userdata[$val]);
            }*/

Code:
// Serialize the custom data array so we can store it
            $custom_userdata = serialize($custom_userdata);
        }
        
        // Run the update query
        $this->CI->db->where('session_id', $this->userdata['session_id']);
        $this->CI->db->update($this->sess_table_name, array('last_activity' => $this->userdata['last_activity'], 'user_data' => $custom_userdata));

        // Write the cookie.  Notice that we manually pass the cookie data array to the
        // _set_cookie() function. Normally that function will store $this->userdata, but
        // in this case that array contains custom data, which we do not want in the cookie.
        $this->_set_cookie($cookie_userdata);
    }

I have attached a copy of this file with .txt appended, I think these changes should be incorporated into the copy in SVN, I just don't have access otherwise I would do it.
#7

[eluser]newsun[/eluser]
I was hoping someone who has svn access would have read the last part about fixing the Session.php file. Or maybe give me a direction on where to post or how to get access to commit a change.
#8

[eluser]tomcode[/eluser]
If You'll have no answer from one of the CI crew (not sure there working the weekend) I suggest You to repost with specifying the svn version in the title.

You can also go to the Bug tracker. Chances are that You'll find it there already.
#9

[eluser]Derek Jones[/eluser]
Hi newsun, I don't see the file attachment. Do you mind zipping your Session.php file and attaching it here? I'll be happy to take a look at it.
#10

[eluser]newsun[/eluser]
Hmm, yeah looks like my original attachment did not hold. He is another attempt to attach Session.php as Session.zip compressed file.




Theme © iAndrew 2016 - Forum software by © MyBB