ExpressionEngine CMS
Open, Free, Amazing

Thread

This is an archived forum and the content is probably no longer relevant, but is provided here for posterity.

The active forums are here.

NGSession: a combination of CI’s Session in 1.6 and DBSession

February 02, 2008 12:14pm

Subscribe [14]
  • #31 / Mar 24, 2008 9:39pm

    kirilisa

    20 posts

    Hi folks,

    I recently made a post about some security problems that I felt existed in NGSession - but I put the post as a new topic (I thought I’d hit Reply but whoops) by mistake and I don’t think I can move it.

    Anyway, the topic is here if anyone wants to read it Thread 74428. In short, things that seem to me problems are:

    1) When sess_update() is called, the new session ID does not actually get written to the DB, i.e. the session is never in fact updated [because userdata[‘session_id’] is unset & never stored in sess_write_database()]
    2) NGSession does an IP matching check and User Agent matching check when selecting from the DB in sess_read() whether you have set those options to TRUE in your config file or not
    3) I also felt that the names ip_address, user_agent, and last_activity were too generic and thus have a fairly decent chance of being overwritten manually by mistake so I renamed them (not shown in code below)

    I updated the code to fix the above issues for my own purposes, but I thought I’d post the relevant methods here too, in case anyone wants them. The changes are really quite minor and are marked with //@@@.

    Of course, if I have updated it wrong, or understood something wrong, please correct me!

    This code only includes the relevant methods!

    /* mysql table creation 
     *
     * CREATE TABLE `ci_sessions` (                                                                                                                      
     * `session_id` varchar(40) NOT NULL default '0',                                                                                                    
     * `sess_ip_address` varchar(16) NOT NULL default '0',                                                                                               
     * `sess_user_agent` varchar(50) NOT NULL,                                                                                                           
     * `sess_last_update` int(10) unsigned NOT NULL default '0',                                                                                         
     * `session_data` text,                                                                                                                              
     * PRIMARY KEY  (`session_id`)                                                                                                                       
     * ) ENGINE=MyISAM DEFAULT CHARSET=utf8; 
    */
    
    function sess_read() {
       ...
        // database mode - no need to check if all fields are required - just get them all                                                               
        if ($this->use_database == TRUE) {                                                          
            //@@@ check IP and user agent only if specified by config!                                                                                   
            $this->CI->db->where('session_id', $this->session_id);
            if ($this->CI->config->item('sess_match_ip') == TRUE) $this->CI->db->where('sess_ip_address', $this->CI->input->ip_address());
            if ($this->CI->config->item('sess_match_useragent') == TRUE) $this->CI->db->where('sess_user_agent', trim(substr($this->CI->input->user_agent(), 0, 50)));
      ...
      }
    
      function sess_write_database($update=FALSE)
      {
        // get current user agent and IP address; format data to match database structure                                                                
        $db_data = array
          (                                                                         
           'sess_ip_address'=> $this->userdata['sess_ip_address'],
           'sess_user_agent'=> $this->userdata['sess_user_agent'],
           'sess_last_update'=> $this->userdata['sess_last_update']
           );
    
        //@@@ if this is an update, include new session id                                                                                               
        if ($update) $db_data['session_id'] = $update;
                   
        // now serialize only the userdata part                                                                                                          
        $db_userdata = $this->userdata;
        unset($db_userdata['session_id']);
        unset($db_userdata['sess_ip_address']);
        unset($db_userdata['sess_user_agent']);
        unset($db_userdata['sess_last_update']);
        $db_data['session_data'] = serialize($db_userdata);
    
        // update database (matching against old session id)                                                                                                                            
        $this->CI->db->query($this->CI->db->update_string($this->session_table, $db_data, array('session_id' => $this->session_id)));
    
        //@@@ now set new session id for cookie writing                                                                                                       
        if ($update) $this->session_id = $update;
      }
         
      function sess_update()
      {
        $new_sessid = '';
        while (strlen($new_sessid) < 32) {
            $new_sessid .= mt_rand(0, mt_getrandmax());
        }
        $new_sessid = md5(uniqid($new_sessid, TRUE));
    
        // Update the session data in the session data array                                                                                             
        $this->userdata['session_id'] = $new_sessid;
        $this->userdata['sess_last_update'] = $this->now;
    
        //@@@ database mode - update the session id in the db                                                                                               
        if ($this->use_database == TRUE) {
            $this->sess_write_database($new_sessid);
        }
    
        // Write the cookie                                                                                                                              
        $this->sess_write_cookie();
    
      }

    I think that’s it. Hopefully I didn’t forget anything while cutting and pasting!

  • #32 / Mar 26, 2008 5:32am

    WolfgangA

    46 posts

    Hello kirilisa,

    thank you for pointing out these issues.

    I am going to release a new version so hopefully this will be fixed, too.

    Regards

    Wolfgang

  • #33 / Jul 01, 2008 9:50am

    Lone

    350 posts

    kirilisa: Thanks for those updates - we actually came across the IP matching error a few weeks back and made those fixes as well.

    Late reply from me as well as I just worked out it was this session library we were using and not the DBsession one!

  • #34 / Jul 24, 2008 11:54am

    Raf31

    6 posts

    This library looks to be a great and more secure alternative to the original session library. However, it seems that it has not been updated yet to include all the improvements proposed by Webthink and Kirilisa. WolfgangA, do you plan to do it? Or did someone made the change and could provide it here?

  • #35 / Oct 20, 2008 9:08pm

    OverZealous

    1030 posts

    I think I have found a bug when using NG_Session with Safari (on Mac).

    Apparently, the query that is inserting into the database is inserting NULL for the session_data.  I haven’t figured out why yet, but Safari never sees the session data.  Everything works fine on FF and Opera.

    Anyone else see this problem?

    UPDATE: I should mention that it works fine if I swap the original Session back in.

    UPDATE 2: Apparently, I’m not sure how or why, the session key that is inserted into the database is different than the one that is used for updates.  The key that I see in my ci_sessions table does not occur anywhere in the debug log for NG_Sessions.

    UPDATE 3: It’s the user_agent - apparently there is something wrong with Safari’s user agent where it won’t match (at least, under PostGreSQL).  The user agent string:

    'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_5; '

    I think it’s related to that hanging space, which apparently is part of the user_agent string.  NG_Sessions is apparently trimming the UA on the where, but not on the insert.  Removing the trim() from sess_read() seems to have fixed it.

.(JavaScript must be enabled to view this email address)

ExpressionEngine News!

#eecms, #events, #releases