SitePoint Sponsor

User Tag List

Results 1 to 19 of 19

Thread: User Sessions

  1. #1
    SitePoint Zealot
    Join Date
    Mar 2007
    Posts
    196
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    User Sessions

    OK now that I have finally gotten opinions from many on how to hash and protect users passwords I am ready to stir up discussion about users sessions. I am still pretty new to this and the one thing I know for sure is not to store a users password in a session. The biggest thing to me is validating the user with the sessions because I have been told on a shared server other users can tamper with these sessions. So feel free to give me your input on this topic.
    Kayzio - We don't hesitate, we accelerate.

  2. #2
    Worship the Krome kromey's Avatar
    Join Date
    Sep 2006
    Location
    Fairbanks, AK
    Posts
    1,621
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Google: session hijacking

    Actually, I'm sure a search on this forum will turn up a lot about it. There's been many methods suggested for avoiding it, including storing the User Agent string in a session and/or storing the user's IP (or subnet).

    As for making sure other users on the server don't tamper with your sessions, I don't think there's anything you can do about that. Do as much verification as you reasonably can on session data, but you can't really stop them in a shared hosting environment.

    Actually, one method I saw once was as follows:
    Concatenate every session variable value into one long string, hash it with a secret key, and store that in your session (when concatenating session variables, don't include this hash). Do this at the end of every script (to catch any/all updates you make during the script), and at the beginning of every script verify it. This gives you a nearly-foolproof method for catching any tampering of your session data.

    Code php:
    $secretkey = "Some secret key hard-coded into your scripts";
    $sess_str = "";
    foreach($_SESSION as $key=>$val)
    {
        if($key == "checksum") continue; //don't include the hash
        $sess_str .= $val;
    }
    $hash = sha1($sess_str.$secretkey);
    if($hash != $_SESSION['checksum'])
    {
        //session tampering! abort! terminate!
    }
    Repeat the procedure to generate the checksum at the end of the script, and instead of checking it store it in $_SESSION['checksum'].

    All that said, I don't think this is worth the effort. It's going to slow down your scripts, and to be perfectly frank I don't think you need to worry about other users in your shared hosting environment tampering with your sessions. It's just not worth it.

    If you are worried about someone tampering with your sessions, then write your own session handling method that stores everything in your database. That way there are no files in the temp directory for anyone to mess with. This is the method I use, although I chose to do so a) for the experience and b) so that I could easily scale up to a giant, load-balanced server farm (albeit a very unlikely happenstance). My database-based sessions are at least as fast as PHP's file-based session (database reads are often faster than file system accesses, and unless the database is poorly designed are almost never slower), and they are more secure because no one can get to my temp files because I don't have any (although that's not a concern in my case since I'm on a virtual dedicated server).
    PHP questions? RTFM
    MySQL questions? RTFM

  3. #3
    SitePoint Zealot
    Join Date
    Mar 2007
    Posts
    196
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    how exactly do you go about database sessions? for example when a page loads how do I check the database to see if they are logged in? Do I have to perform a query that searches for there ip in the database or something? I have thought about learning to do database sessions but never found any good in depth tutorials on it.
    Kayzio - We don't hesitate, we accelerate.

  4. #4
    SitePoint Zealot
    Join Date
    Mar 2007
    Posts
    196
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Never mind I finally came across one that looks good: http://www.devshed.com/c/a/PHP/Stori...in-a-Database/
    Kayzio - We don't hesitate, we accelerate.

  5. #5
    SitePoint Wizard wonshikee's Avatar
    Join Date
    Jan 2007
    Posts
    1,223
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    This is what I do, maybe I could get some feedback on my method.

    1) Store their session id and a hashed flag consisting of their USER_AGENT and a simple salt.

    2) if a session id is set, ie logged in, then at the top of every pageload - regenerate_session_id() so that everytime the user does something - they are given a new ID.

    3) on pages that require login, make sure that they have a session ID, and the session flag matches the server user_agent, which should since a user's ip may change but they can't use different browsers with the same session. if its different, kill the whole session.

  6. #6
    Worship the Krome kromey's Avatar
    Join Date
    Sep 2006
    Location
    Fairbanks, AK
    Posts
    1,621
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    That's one way to do it. I built my session handler from scratch. Essentially I created a new database table, sessions, that does little more than store a session ID and link that to a user ID in the users table. Each time a page loads, I check if the session cookie exists, and if it does I look up the ID stored in it in my session table; if I find it, I load up that user's data into my user object. If the cookie doesn't exist or the session isn't in my table, the user isn't logged in and I redirect them to the login page.

    I said "little more"; I also store a session expiration time so that I know when a session expires. Additionally, I store session variables in name=value pairs delineated by the '&' character (just like GET parameters in a URL); PHP has a handy function called parse_str for extrapolating data stored like that. Thus I have all the flexibility of PHP's sessions with the power of being fully database-based. And I have a deep understanding of what exactly sessions are and how exactly they work, more so than someone who merely reads just enough to know how to use $_SESSION.
    PHP questions? RTFM
    MySQL questions? RTFM

  7. #7
    Worship the Krome kromey's Avatar
    Join Date
    Sep 2006
    Location
    Fairbanks, AK
    Posts
    1,621
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by wonshikee View Post
    This is what I do, maybe I could get some feedback on my method.

    1) Store their session id and a hashed flag consisting of their USER_AGENT and a simple salt.

    2) if a session id is set, ie logged in, then at the top of every pageload - regenerate_session_id() so that everytime the user does something - they are given a new ID.

    3) on pages that require login, make sure that they have a session ID, and the session flag matches the server user_agent, which should since a user's ip may change but they can't use different browsers with the same session. if its different, kill the whole session.
    I think regenerating the session ID on every page load is perhaps a bit excessive, but if it's working for you then don't let me stop you. I'd do a little more than merely check for a session ID to verify that a user is logged in (like verify your hashed user agent string), but I'm sure you do do that and you merely neglected to mention so.
    Edit:


    Oh, you did mention that you do more to validate... I should have read your post more closely. I apologize.
    PHP questions? RTFM
    MySQL questions? RTFM

  8. #8
    SitePoint Wizard wonshikee's Avatar
    Join Date
    Jan 2007
    Posts
    1,223
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kromey View Post
    I think regenerating the session ID on every page load is perhaps a bit excessive, but if it's working for you then don't let me stop you. I'd do a little more than merely check for a session ID to verify that a user is logged in (like verify your hashed user agent string), but I'm sure you do do that and you merely neglected to mention so.
    #3 the session flag matches the server user_agent

    maybe i worded it terribly, i don't blame you for not understanding me but thats what it said.

    I only regenerate logged in users - which would alleviate as much load as possible since its an auction site and many will browse through without actually logging in.

  9. #9
    Worship the Krome kromey's Avatar
    Join Date
    Sep 2006
    Location
    Fairbanks, AK
    Posts
    1,621
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    One more note on regenerating session ID every time - I could be mistaken, but I believe PHP generates a new session file in your temp directory each time a new session ID is generated. Thus, a user who browses across 20 pages will have 20 files in your temp directory, since PHP only cleans up the directory every so often and only when such a file has expired (as per session.expire or whatever it's called). So this would be a very bad idea for a high-traffic site because you'd fill up your entire disk with these orphaned sessions. Should be fine for a low-traffic site, however, except that the increased file system access could slow you down.
    PHP questions? RTFM
    MySQL questions? RTFM

  10. #10
    SitePoint Wizard wonshikee's Avatar
    Join Date
    Jan 2007
    Posts
    1,223
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kromey View Post
    One more note on regenerating session ID every time - I could be mistaken, but I believe PHP generates a new session file in your temp directory each time a new session ID is generated. Thus, a user who browses across 20 pages will have 20 files in your temp directory, since PHP only cleans up the directory every so often and only when such a file has expired (as per session.expire or whatever it's called). So this would be a very bad idea for a high-traffic site because you'd fill up your entire disk with these orphaned sessions. Should be fine for a low-traffic site, however, except that the increased file system access could slow you down.
    I'm not sure on the technicalities of whether it creates a new file - or rewrites just the SESSID. But here's something to answer ur second half
    5.1.0 Added the delete_old_session parameter.

    It would imply that a new file is created. But I dunno myself.

  11. #11
    SitePoint Zealot
    Join Date
    Mar 2007
    Posts
    196
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yea I plan to go strictly database driven with sessions and in the article I found it talks about how database sessions are a lot more friendly when it comes to large sites running on multiple servers.
    Kayzio - We don't hesitate, we accelerate.

  12. #12
    SitePoint Zealot
    Join Date
    Mar 2007
    Posts
    196
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Here is what I have so far:
    PHP Code:
    <?php

        
    class SessionManager {

            
    /**
            * When True Error Reporting Is Enabled
            *
            * @public bool
            */
            
    public $ErrorReporting false;

            
    /**
            * Session Life Time
            *
            * @public bool
            */
            
    public $LifeTime;

            
    /**
            * Close
            */
            
    function Close() {
                return 
    true;
            }

            
    /**
            * Destroy
            *
            * @param int
            */
            
    function Destroy($ID) {
                
    $NewID mysql_real_escape_string($ID);
                
    $SessionData $DB->Query("DELETE FROM sessions WHERE id = '$NewID'");
                return 
    true;
            }

            
    /**
            * Garbage Collection
            */
            
    function GarbageCollection() {
                
    $SessionData $DB->Query("DELETE FROM sessions WHERE expires < time()");
                return 
    true;
            }

            
    /**
            * Session Manager
            */
            
    function Manager() {
                
    $this->LifeTime get_cfg_var("session.gc_maxlifetime");
                
    session_set_save_handler(
                    array(&
    $this"Open"),
                    array(&
    $this"Close"),
                    array(&
    $this"Read"),
                    array(&
    $this"Write"),
                    array(&
    $this"Destroy"),
                    array(&
    $this"GarbageCollection")
                );
            }

            
    /**
            * Open
            *
            * @params string, string
            */
            
    function Open($SavePath$SessionName) {
                global 
    $sess_save_path;
                
    $sess_save_path $SavePath;
                return 
    true;
            }

            
    /**
            * Read
            *
            * @param int
            */
            
    function Read($ID) {
                
    $Data "";
                
    $Time time();
                
    $NewID mysql_real_escape_string($ID);
                
    $SessionData $DB->Query("SELECT data FROM sessions WHERE id = '$NewID' AND expires > $Time");
                
    $NumRows $DB->NumRows($SessionData);
                if (
    $NumRows 0) {
                    
    $Row $DB->FetchAssoc($SessionData);
                    
    $Data $Row['data'];
                }
                return 
    $Data;
            }

            
    /**
            * Write
            *
            * @params int, string
            */
            
    function Write($ID$Data) {
                
    $Time time() + $this->LifeTime;
                
    $NewID mysql_real_escape_string($ID);
                
    $NewData mysql_real_escape_string($Data);
                
    $ReplaceSession $DB->Query("REPLACE sessions (id, data, expires) VALUES ($NewID$NewData$Time)");
                return 
    true;
            }

        }

    ?>
    I basically rewrote what I saw in some tutorials but changed a few things here and there to come up with the above class. Something I would like to know is would it be very hard to write a function similar to mysql_real_escape_string b/c I want this class to work with multiple database types.
    Kayzio - We don't hesitate, we accelerate.

  13. #13
    Worship the Krome kromey's Avatar
    Join Date
    Sep 2006
    Location
    Fairbanks, AK
    Posts
    1,621
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I'd simply use mysql_real_escape_string when using MySQL, and addslashes otherwise. Or, better yet, just use PDO.
    PHP questions? RTFM
    MySQL questions? RTFM

  14. #14
    SitePoint Zealot
    Join Date
    Mar 2007
    Posts
    196
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for the tip kromey.
    Kayzio - We don't hesitate, we accelerate.

  15. #15
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Generating a new session id on each page load is a bad idea. It effectively prevents the user from having multiple windows open to the same site (using tabbed browsing for example). It's not needed either. To prevent session-hijacking, you just need to regenerate id when users privileges changes (eg. when a user logs in).

  16. #16
    SitePoint Wizard wonshikee's Avatar
    Join Date
    Jan 2007
    Posts
    1,223
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    Generating a new session id on each page load is a bad idea. It effectively prevents the user from having multiple windows open to the same site (using tabbed browsing for example). It's not needed either. To prevent session-hijacking, you just need to regenerate id when users privileges changes (eg. when a user logs in).
    Was not aware it affected tabbed browsing, thanks.

  17. #17
    SitePoint Zealot
    Join Date
    Mar 2007
    Posts
    196
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    good point wonshikee, never looked at it like that. I am glad I didn't write out all of that code. Also any suggestions to improve what I have.
    Kayzio - We don't hesitate, we accelerate.

  18. #18
    Worship the Krome kromey's Avatar
    Join Date
    Sep 2006
    Location
    Fairbanks, AK
    Posts
    1,621
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Two comments Kayzio:
    The first is more of a nitpick - your comments indicate that $LifeTime is a bool when it is in fact an int.

    The second is especially relevant given your desire to make this compatible with more than one database: REPLACE is a MySQL-specific extension of the SQL standard and thus will not work on other databases. I'd suggest rewriting that as an UPDATE statement (in your Write method).
    PHP questions? RTFM
    MySQL questions? RTFM

  19. #19
    SitePoint Zealot
    Join Date
    Mar 2007
    Posts
    196
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    nice find lol and thanks for letting me know replace is mysql only i'll make sure i fix that
    Kayzio - We don't hesitate, we accelerate.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •