SitePoint Sponsor

User Tag List

Results 1 to 9 of 9
  1. #1
    jigga jigga what? slider's Avatar
    Join Date
    Oct 2002
    Location
    Utah (USA)
    Posts
    309
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Session hijacking

    Wow... I just watched somebody hijack a session and it amazed me how easy it was. The person that did it is not even close to technical (he's one of our salesmen). We got access to a "protected" PHP site for a law school back east.

    I know these conversations are a dime a dozen on the forum here, but just wanted to get a perspective on the case of keeping session id out of the URL for security, but making your web app still usable by those that may not have cookies enabled or whatever else may keep them from using a session based login without having the session id in the URL.
    $slider = 'n00b';

  2. #2
    ********* Genius Mike's Avatar
    Join Date
    Apr 2001
    Location
    Canada
    Posts
    5,458
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Keep the session in a database.

    In my script, I have it make the user enter their password again if they are about to edit sensitive information, or if they have been idle for more than 5 minutes. It saves whatever action they were doing, so no info they may have entered into a form is wrong, it just makes them go through one extra step.

    You could also kill the session if the IP used to login is different than the one accessing the page, but that won't work with AOL, so you'd have to check for that first.
    Mike
    It's not who I am underneath, but what I do that defines me.

  3. #3
    Mlle. Ledoyen silver trophy seanf's Avatar
    Join Date
    Jan 2001
    Location
    UK
    Posts
    7,168
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    That still leaves the possibility of hijacking sessions through a URL though Mike. It may eliminate users who don't accept cookies, but setting session.use_only_cookies on will stop session hijacking in this way

    [Edit] Hey! You edited your post

    Sean
    Harry Potter

    -- You lived inside my world so softly
    -- Protected only by the kindness of your nature

  4. #4
    ********* Genius Mike's Avatar
    Join Date
    Apr 2001
    Location
    Canada
    Posts
    5,458
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Yes, you'd have to make sure the SID didn't get put into the URL by the server if you're using a database.

    And
    Mike
    It's not who I am underneath, but what I do that defines me.

  5. #5
    Sidewalking anode's Avatar
    Join Date
    Mar 2001
    Location
    Philadelphia, US
    Posts
    2,205
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Sean and Mike can you guys go into more depth about the keeping session info in the DB concept? I'm having hard time figuring my head around how to implement it.
    TuitionFree a free library for the self-taught
    Anode Says... Blogging For Your Pleasure

  6. #6
    ********* Genius Mike's Avatar
    Join Date
    Apr 2001
    Location
    Canada
    Posts
    5,458
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    I have some code here, although I'm not sure how good/secure/efficient it is. I'll post in a few....
    Mike
    It's not who I am underneath, but what I do that defines me.

  7. #7
    Mlle. Ledoyen silver trophy seanf's Avatar
    Join Date
    Jan 2001
    Location
    UK
    Posts
    7,168
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You simply create a custom session handler to store the session data in your database. The manual has tonnes of information on how to do this here. This will stop other people on the same server being able to access data that is stored in the session files

    Sean
    Harry Potter

    -- You lived inside my world so softly
    -- Protected only by the kindness of your nature

  8. #8
    Sidewalking anode's Avatar
    Join Date
    Mar 2001
    Location
    Philadelphia, US
    Posts
    2,205
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I think I'm missing something. While this way is more convenient, the benefits can be replicated by putting the session savepath into a directory only you can access, right? Does it make any allowances for session hijacking through URL's?
    TuitionFree a free library for the self-taught
    Anode Says... Blogging For Your Pleasure

  9. #9
    ********* Genius Mike's Avatar
    Join Date
    Apr 2001
    Location
    Canada
    Posts
    5,458
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    OK, first off, it requires PEAR (http://pear.php.net/package-info.php?pacid=14) and this class:
    http://pear.php.net/package-info.php?pacid=46

    First off, make a table called php_session in a database:

    Code:
    CREATE TABLE php_session (
      id CHAR(32) NOT NULL,
      data MEDIUMBLOB,
      last_access INT UNSIGNED NOT NULL,
      PRIMARY KEY(id)
    )

    OK, to start the session:

    PHP Code:
    include 'sessionscript.php';
    $s = new pc_DB_Session('mysql://user:password@localhost/db');
    ini_get('session.auto_start') or session_start(); 

    And the sessionscript.php:

    PHP Code:
    require 'PEAR.php';
    require 
    'DB.php';

    class 
    pc_DB_Session extends PEAR {

        var 
    $_dbh;
        var 
    $_table;
        var 
    $_connected false;
        var 
    $_gc_maxlifetime;
        var 
    $_prh_read;
        var 
    $error null;

        
    /**
         * Constructor
         */
        
    function pc_DB_Session($dsn null) {
            if (
    is_null($dsn)) { 
                
    $this->error PEAR::raiseError('No DSN specified');
                return;
            }

            
    $this->_gc_maxlifetime ini_get('session.gc_maxlifetime');
            
    // Sessions last for a day unless otherwise specified. 
            
    if (! $this->_gc_maxlifetime) {
                
    $this->_gc_maxlifetime 86400;
            }

            
    $this->_table ini_get('session.save_path');
            if ((! 
    $this->_table) || ('/tmp' == $this->_table)) {
                
    $this->_table 'php_session';
            }

            
    $this->_dbh DB::connect($dsn);
            if (
    DB::isError($this->_dbh)) {
                
    $this->error $this->_dbh;
                return;
            }

            
    $this->_prh_read $this->_dbh->prepare(
                
    "SELECT data FROM $this->_table WHERE id LIKE ? AND last_access >= ?");
            if (
    DB::isError($this->_prh_read)) {
                
    $this->error $this->_prh_read;
                return;
            }

            if (! 
    session_set_save_handler(array(&$this,'_open'),
                                           array(&
    $this,'_close'),
                                           array(&
    $this,'_read'),
                                           array(&
    $this,'_write'),
                                           array(&
    $this,'_destroy'),
                                           array(&
    $this,'_gc'))) {
                
    $this->error PEAR::raiseError('session_set_save_handler() failed');
                return;
            }

            return 
    $this->_connected true;
        }

        function 
    _open() {
            return 
    $this->_connected;
        }
        
        function 
    _close() {
            return 
    $this->_connected;
        }

        function 
    _read($id) {
            if (! 
    $this->_connected) { return false; }
            
    $sth 
                
    $this->_dbh->execute($this->_prh_read,
                                     array(
    $id,time() - $this->_gc_maxlifetime));
            if (
    DB::isError($sth)) {
                
    $this->error $sth;
                return 
    '';
            } else {
                if ((
    $sth->numRows() == 1) && 
                    (
    $ar $sth->fetchRow(DB_FETCHMODE_ORDERED))) {
                    return 
    $ar[0];
                } else {
                    return 
    '';
                }
            }
        }

        function 
    _write($id,$data) {
            
    $sth $this->_dbh->query(
                
    "REPLACE INTO $this->_table (id,data,last_access) VALUES (?,?,?)"
                array(
    $id,$data,time()));
            if (
    DB::isError($sth)) {
                
    $this->error $sth;
                return 
    false;
            } else {
                return 
    true;
            }
        }

        function 
    _destroy($id) {
            
    $sth $this->_dbh->query("DELETE FROM $this->_table WHERE id LIKE ?",
                                      array(
    $id));
            if (
    DB::isError($sth)) {
                
    $this->error $sth;
                return 
    false;
            } else {
                return 
    true;
            }
        }

        function 
    _gc($maxlifetime) {
            
    $sth $this->_dbh->query("DELETE FROM $this->_table WHERE last_access < ?"
                                      array(
    time() - $maxlifetime));
            if (
    DB::isError($sth)) {
                
    $this->error $sth;
                return 
    false;
            } else {
                return 
    true;
            }
        }

    That's straight from the book "PHP Cookbook".
    Mike
    It's not who I am underneath, but what I do that defines me.


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
  •