Make Your Sessions More Secure

  • astkboy2008
  • Born
  • Born
  • astkboy2008
  • Posts: 3

Post 3+ Months Ago

Storing session data in a MySQL required a php class. This class implements a new PHP session handler that can replace the default PHP session handler by storing session data in a MySQL database table.

The session handler works just by creating an object of this class. After that, applications just need to use the same code to store and retrieve session variables. How can I use it? It's very easy - just see this example:

Code: [ Select ]
<?php

  // first create the required mySQL table that is used by this class
  // you can do that by running in mySQL the "session_data.sql" file
  // from the "install" folder!
  
  // change the next values to match the setting of your mySQL database
  $mySQLHost = "localhost";
  $mySQLUsername = "username";
  $mySQLPassword = "password";
  
  // this is the name of the database where you created the table
  // used by this class
  $mySQLDatabase = "database";
  
  $link = mysql_connect($mySQLHost, $mySQLUsername, $mySQLPassword);

  if (!$link) {

    die ("Could not connect to database!");

  }

  $db = mysql_select_db($mySQLDatabase, $link);

  if (!$db) {

    die ("Could not select database!");

  }

  // include the session manager class
  require "../class.dbsession.php";
  
  // instantiate a new session object
  // note that you don't need to call the session_start() function
  // as it is called automatically when the object is instantiated
  $session = new dbsession();

  // from now on, use sessions as you would normally
  // the only difference is that session data is no longer saved on the server
  // but in your database, making the data in it more secure
  
  print_r("
    The first time you run the script there should be an empty array (as there's nothing in the
\$_SESSION array)<br />
    After you press \"refresh\" on your browser you will se the values that were
written in the \$_SESSION array<br>
  ");
  print_r("<pre>");
  print_r($_SESSION);
  print_r("</pre>");

  // add some values to the session
  $_SESSION["value1"] = "hello";
  $_SESSION["value2"] = "world";
  
  // now check the table and see that there is data in it!
  
  // to completely delete a session uncomment the following line
  
  //$session->stop();
?>
  1. <?php
  2.   // first create the required mySQL table that is used by this class
  3.   // you can do that by running in mySQL the "session_data.sql" file
  4.   // from the "install" folder!
  5.   
  6.   // change the next values to match the setting of your mySQL database
  7.   $mySQLHost = "localhost";
  8.   $mySQLUsername = "username";
  9.   $mySQLPassword = "password";
  10.   
  11.   // this is the name of the database where you created the table
  12.   // used by this class
  13.   $mySQLDatabase = "database";
  14.   
  15.   $link = mysql_connect($mySQLHost, $mySQLUsername, $mySQLPassword);
  16.   if (!$link) {
  17.     die ("Could not connect to database!");
  18.   }
  19.   $db = mysql_select_db($mySQLDatabase, $link);
  20.   if (!$db) {
  21.     die ("Could not select database!");
  22.   }
  23.   // include the session manager class
  24.   require "../class.dbsession.php";
  25.   
  26.   // instantiate a new session object
  27.   // note that you don't need to call the session_start() function
  28.   // as it is called automatically when the object is instantiated
  29.   $session = new dbsession();
  30.   // from now on, use sessions as you would normally
  31.   // the only difference is that session data is no longer saved on the server
  32.   // but in your database, making the data in it more secure
  33.   
  34.   print_r("
  35.     The first time you run the script there should be an empty array (as there's nothing in the
  36. \$_SESSION array)<br />
  37.     After you press \"refresh\" on your browser you will se the values that were
  38. written in the \$_SESSION array<br>
  39.   ");
  40.   print_r("<pre>");
  41.   print_r($_SESSION);
  42.   print_r("</pre>");
  43.   // add some values to the session
  44.   $_SESSION["value1"] = "hello";
  45.   $_SESSION["value2"] = "world";
  46.   
  47.   // now check the table and see that there is data in it!
  48.   
  49.   // to completely delete a session uncomment the following line
  50.   
  51.   //$session->stop();
  52. ?>


and the session will store in the mysql after that
  • UPSGuy
  • Lurker ಠ_ಠ
  • Web Master
  • User avatar
  • Posts: 2733
  • Loc: Nashville, TN

Post 3+ Months Ago

I've edited your post for organization and meaningful content. If you would like to continue your example and share the required class code here as well, I am ok with that, but please do not post threads only to redirect to your personal page. We're about learning here - not marketing.

The required file, class.dbsession.php:
Code: [ Select ]
<?php

/**
* A class to handle sessions by using a mySQL database for session related data storage providing
better
* security then the default session handler used by PHP.
*
* To prevent session hijacking, don't forget to use the {@link regenerate_id} method whenever you
do a
* privilege change in your application
*
* <i>Before usage, make sure you use the session_data.sql file from the
<b>install</b> folder to set up the table
* used by the class</i>
*
* After instantiating the class, use sessions as you would normally
*
* This class is an adaptation of John Herren's code from the "Trick out your session
handler" article
* ({@link http://devzone.zend.com/node/view/id/141}) and Chris Shiflett's code from Chapter 8,
Shared Hosting - Pg 78-80,
* of his book - "Essential PHP Security" ({@link http://phpsecurity.org/code/ch08-2})
*
* <i>Note that the class assumes that there is an active connection to a mySQL database and
it does not attempt to create
* one. This is due to the fact that, usually, there is a config file that holds the database
connection related
* information and another class, or function that handles database connection. If this is not how
you do it, you can
* easily adapt the code by putting the database connection related code in the "open"
method of the class.</i>
*
* This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 2.5
License.
* To view a copy of this license, visit {@link http://creativecommons.org/licenses/by-nc-nd/2.5/}
or send a letter to
* Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA.
*
* For more resources visit {@link http://stefangabos.blogspot.com}
*
* @author   Stefan Gabos <ix@nivelzero.ro>
* @version  1.0.1 (last revision: August 11, 2006)
* @copyright (c) 2006 Stefan Gabos
* @package  dbSession
*/

error_reporting(E_ALL);

class dbSession
{

  /**
   * Constructor of class
   *
   * Initializes the class and starts a new session
   *
   * There is no need to call start_session() after instantiating this class
   *
   * @param integer   $gc_maxlifetime   the number of seconds after which data will be seen
as 'garbage' and
   *                     cleaned up on the next run of the gc (garbage
collection) routine
   *
   *                     Default is specified in php.ini file
   *
   * @param integer   $gc_probability   used in conjunction with gc_divisor, is used to
manage probability that
   *                     the gc routine is started. the probability is
expressed by the formula
   *
   *                     probability = $gc_probability / $gc_divisor
   *
   *                     So if $gc_probability is 1 and $gc_divisor is 100
means that there is
   *                     a 1% chance the the gc routine will be called on
each request
   *
   *                     Default is specified in php.ini file
   *
   * @param integer   $gc_divisor     used in conjunction with gc_probability, is used to
manage probability
   *                     that the gc routine is started. the probability is
expressed by the formula
   *
   *                     probability = $gc_probability / $gc_divisor
   *
   *                     So if $gc_probability is 1 and $gc_divisor is 100
means that there is
   *                     a 1% chance the the gc routine will be called on
each request
   *
   *                     Default is specified in php.ini file
   *
   * @return void
   */
  function dbSession($gc_maxlifetime = "", $gc_probability = "", $gc_divisor =
"")
  {

    // if $gc_maxlifetime is specified and is an integer number
    if ($gc_maxlifetime != "" && is_integer($gc_maxlifetime)) {
    
      // set the new value
      @ini_set('session.gc_maxlifetime', $gc_maxlifetime);
      
    }

    // if $gc_probability is specified and is an integer number
    if ($gc_probability != "" && is_integer($gc_probability)) {

      // set the new value
      @ini_set('session.gc_probability', $gc_probability);

    }

    // if $gc_divisor is specified and is an integer number
    if ($gc_divisor != "" && is_integer($gc_divisor)) {

      // set the new value
      @ini_set('session.gc_divisor', $gc_divisor);

    }
    
    // get session lifetime
    $this->sessionLifetime = ini_get("session.gc_maxlifetime");
    
    // register the new handler
    session_set_save_handler(
      array(&$this, 'open'),
      array(&$this, 'close'),
      array(&$this, 'read'),
      array(&$this, 'write'),
      array(&$this, 'destroy'),
      array(&$this, 'gc')
    );
    register_shutdown_function('session_write_close');
    
    // start the session
    session_start();
    
  }
  
  /**
   * Deletes all data related to the session
   *
   * @return void
   */     
  function stop()
  {
    $this->regenerate_id();
    session_unset();
    session_destroy();
  }
  
  /**
   * Regenerates the session id.
   *
   * <b>Call this method whenever you do a privilege change!</b>
   *
   * @return void
   */
  function regenerate_id()
  {

    // saves the old session's id
    $oldSessionID = session_id();
    
    // regenerates the id
    // this function will create a new session, with a new id and containing the data from the
old session
    // but will not delete the old session
    session_regenerate_id();
    
    // because the session_regenerate_id() function does not delete the old session,
    // we have to delete it manually
    $this->destroy($oldSessionID);
    
  }
  
  /**
   * Get the number of online users
   *
   * This is not 100% accurate. It depends on how often the garbage collector is run
   *
   * @return integer   approximate number of users currently online
   */
  function get_users_online()
  {

    // counts the rows from the database
    $result = @mysql_fetch_assoc(@mysql_query("
      SELECT
        COUNT(session_id) as count
      FROM session_data
    "));
    
    // return the number of found rows
    return $result["count"];
    
  }
  
  /**
   * Custom open() function
   *
   * @access private
   */
  function open($save_path, $session_name)
  {
  
    return true;
    
  }
  
  /**
   * Custom close() function
   *
   * @access private
   */
  function close()
  {
    return true;
  }
  
  /**
   * Custom read() function
   *
   * @access private
   */
  function read($session_id)
  {

    // reads session data associated with the session id
    // but only if the HTTP_USER_AGENT is the same as the one who had previously written to this
session
    // and if session has not expired
    $result = @mysql_query("
      SELECT
        session_data
      FROM
        session_data
      WHERE
        session_id = '".$session_id."' AND
        http_user_agent = '".$_SERVER["HTTP_USER_AGENT"]."' AND
        session_expire > '".time()."'
    ");
    
    // if anything was found
    if (is_resource($result) && @mysql_num_rows($result) > 0) {

      // return found data
      $fields = @mysql_fetch_assoc($result);
      // don't bother with the unserialization - PHP handles this automatically
      return $fields["session_data"];
      
    }
    
    // if there was an error return an empty string - this HAS to be an empty string
    return "";
    
  }
  
  /**
   * Custom write() function
   *
   * @access private
   */
  function write($session_id, $session_data)
  {
  
    // first checks if there is a session with this id
    $result = @mysql_query("
      SELECT
        *
      FROM
        session_data
      WHERE
        session_id = '".$session_id."'
    ");
    
    // if there is
    if (@mysql_num_rows($result) > 0) {

      // update the existing session's data
      // and set new expiry time
      $result = @mysql_query("
        UPDATE
          session_data
        SET
          session_data = '".$session_data."',
          session_expire = '".(time() + $this->sessionLifetime)."'
        WHERE
          session_id = '".$session_id."'
      ");
      
      // if anything happened
      if (@mysql_affected_rows()) {
      
        // return true
        return true;
        
      }

    // if this session id is not in the database
    } else {

      // insert a new record
      $result = @mysql_query("
        INSERT INTO
          session_data
            (
              session_id,
              http_user_agent,
              session_data,
              session_expire
            )
          VALUES
            (
              '".$session_id."',
              '".$_SERVER["HTTP_USER_AGENT"]."',
              '".$session_data."',
              '".(time() + $this->sessionLifetime)."'
            )
      ");
      
      // if anything happened
      if (@mysql_affected_rows()) {
      
        // return an empty string
        return "";
        
      }
      
    }
    
    // if something went wrong, return false
    return false;
    
  }
  
  /**
   * Custom destroy() function
   *
   * @access private
   */
  function destroy($session_id)
  {

    // deletes the current session id from the database
    $result = @mysql_query("
      DELETE FROM
        session_data
      WHERE
        session_id = '".$session_id."'
    ");
    
    // if anything happened
    if (@mysql_affected_rows()) {
    
      // return true
      return true;
      
    }

    // if something went wrong, return false
    return false;
    
  }
  
  /**
   * Custom gc() function (garbage collector)
   *
   * @access private
   */
  function gc($maxlifetime)
  {
  
    // it deletes expired sessions from database
    $result = @mysql_query("
      DELETE FROM
        session_data
      WHERE
        session_expire < '".(time() - $maxlifetime)."'
    ");
    
  }
  
}
?>
  1. <?php
  2. /**
  3. * A class to handle sessions by using a mySQL database for session related data storage providing
  4. better
  5. * security then the default session handler used by PHP.
  6. *
  7. * To prevent session hijacking, don't forget to use the {@link regenerate_id} method whenever you
  8. do a
  9. * privilege change in your application
  10. *
  11. * <i>Before usage, make sure you use the session_data.sql file from the
  12. <b>install</b> folder to set up the table
  13. * used by the class</i>
  14. *
  15. * After instantiating the class, use sessions as you would normally
  16. *
  17. * This class is an adaptation of John Herren's code from the "Trick out your session
  18. handler" article
  19. * ({@link http://devzone.zend.com/node/view/id/141}) and Chris Shiflett's code from Chapter 8,
  20. Shared Hosting - Pg 78-80,
  21. * of his book - "Essential PHP Security" ({@link http://phpsecurity.org/code/ch08-2})
  22. *
  23. * <i>Note that the class assumes that there is an active connection to a mySQL database and
  24. it does not attempt to create
  25. * one. This is due to the fact that, usually, there is a config file that holds the database
  26. connection related
  27. * information and another class, or function that handles database connection. If this is not how
  28. you do it, you can
  29. * easily adapt the code by putting the database connection related code in the "open"
  30. method of the class.</i>
  31. *
  32. * This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 2.5
  33. License.
  34. * To view a copy of this license, visit {@link http://creativecommons.org/licenses/by-nc-nd/2.5/}
  35. or send a letter to
  36. * Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA.
  37. *
  38. * For more resources visit {@link http://stefangabos.blogspot.com}
  39. *
  40. * @author   Stefan Gabos <ix@nivelzero.ro>
  41. * @version  1.0.1 (last revision: August 11, 2006)
  42. * @copyright (c) 2006 Stefan Gabos
  43. * @package  dbSession
  44. */
  45. error_reporting(E_ALL);
  46. class dbSession
  47. {
  48.   /**
  49.    * Constructor of class
  50.    *
  51.    * Initializes the class and starts a new session
  52.    *
  53.    * There is no need to call start_session() after instantiating this class
  54.    *
  55.    * @param integer   $gc_maxlifetime   the number of seconds after which data will be seen
  56. as 'garbage' and
  57.    *                     cleaned up on the next run of the gc (garbage
  58. collection) routine
  59.    *
  60.    *                     Default is specified in php.ini file
  61.    *
  62.    * @param integer   $gc_probability   used in conjunction with gc_divisor, is used to
  63. manage probability that
  64.    *                     the gc routine is started. the probability is
  65. expressed by the formula
  66.    *
  67.    *                     probability = $gc_probability / $gc_divisor
  68.    *
  69.    *                     So if $gc_probability is 1 and $gc_divisor is 100
  70. means that there is
  71.    *                     a 1% chance the the gc routine will be called on
  72. each request
  73.    *
  74.    *                     Default is specified in php.ini file
  75.    *
  76.    * @param integer   $gc_divisor     used in conjunction with gc_probability, is used to
  77. manage probability
  78.    *                     that the gc routine is started. the probability is
  79. expressed by the formula
  80.    *
  81.    *                     probability = $gc_probability / $gc_divisor
  82.    *
  83.    *                     So if $gc_probability is 1 and $gc_divisor is 100
  84. means that there is
  85.    *                     a 1% chance the the gc routine will be called on
  86. each request
  87.    *
  88.    *                     Default is specified in php.ini file
  89.    *
  90.    * @return void
  91.    */
  92.   function dbSession($gc_maxlifetime = "", $gc_probability = "", $gc_divisor =
  93. "")
  94.   {
  95.     // if $gc_maxlifetime is specified and is an integer number
  96.     if ($gc_maxlifetime != "" && is_integer($gc_maxlifetime)) {
  97.     
  98.       // set the new value
  99.       @ini_set('session.gc_maxlifetime', $gc_maxlifetime);
  100.       
  101.     }
  102.     // if $gc_probability is specified and is an integer number
  103.     if ($gc_probability != "" && is_integer($gc_probability)) {
  104.       // set the new value
  105.       @ini_set('session.gc_probability', $gc_probability);
  106.     }
  107.     // if $gc_divisor is specified and is an integer number
  108.     if ($gc_divisor != "" && is_integer($gc_divisor)) {
  109.       // set the new value
  110.       @ini_set('session.gc_divisor', $gc_divisor);
  111.     }
  112.     
  113.     // get session lifetime
  114.     $this->sessionLifetime = ini_get("session.gc_maxlifetime");
  115.     
  116.     // register the new handler
  117.     session_set_save_handler(
  118.       array(&$this, 'open'),
  119.       array(&$this, 'close'),
  120.       array(&$this, 'read'),
  121.       array(&$this, 'write'),
  122.       array(&$this, 'destroy'),
  123.       array(&$this, 'gc')
  124.     );
  125.     register_shutdown_function('session_write_close');
  126.     
  127.     // start the session
  128.     session_start();
  129.     
  130.   }
  131.   
  132.   /**
  133.    * Deletes all data related to the session
  134.    *
  135.    * @return void
  136.    */     
  137.   function stop()
  138.   {
  139.     $this->regenerate_id();
  140.     session_unset();
  141.     session_destroy();
  142.   }
  143.   
  144.   /**
  145.    * Regenerates the session id.
  146.    *
  147.    * <b>Call this method whenever you do a privilege change!</b>
  148.    *
  149.    * @return void
  150.    */
  151.   function regenerate_id()
  152.   {
  153.     // saves the old session's id
  154.     $oldSessionID = session_id();
  155.     
  156.     // regenerates the id
  157.     // this function will create a new session, with a new id and containing the data from the
  158. old session
  159.     // but will not delete the old session
  160.     session_regenerate_id();
  161.     
  162.     // because the session_regenerate_id() function does not delete the old session,
  163.     // we have to delete it manually
  164.     $this->destroy($oldSessionID);
  165.     
  166.   }
  167.   
  168.   /**
  169.    * Get the number of online users
  170.    *
  171.    * This is not 100% accurate. It depends on how often the garbage collector is run
  172.    *
  173.    * @return integer   approximate number of users currently online
  174.    */
  175.   function get_users_online()
  176.   {
  177.     // counts the rows from the database
  178.     $result = @mysql_fetch_assoc(@mysql_query("
  179.       SELECT
  180.         COUNT(session_id) as count
  181.       FROM session_data
  182.     "));
  183.     
  184.     // return the number of found rows
  185.     return $result["count"];
  186.     
  187.   }
  188.   
  189.   /**
  190.    * Custom open() function
  191.    *
  192.    * @access private
  193.    */
  194.   function open($save_path, $session_name)
  195.   {
  196.   
  197.     return true;
  198.     
  199.   }
  200.   
  201.   /**
  202.    * Custom close() function
  203.    *
  204.    * @access private
  205.    */
  206.   function close()
  207.   {
  208.     return true;
  209.   }
  210.   
  211.   /**
  212.    * Custom read() function
  213.    *
  214.    * @access private
  215.    */
  216.   function read($session_id)
  217.   {
  218.     // reads session data associated with the session id
  219.     // but only if the HTTP_USER_AGENT is the same as the one who had previously written to this
  220. session
  221.     // and if session has not expired
  222.     $result = @mysql_query("
  223.       SELECT
  224.         session_data
  225.       FROM
  226.         session_data
  227.       WHERE
  228.         session_id = '".$session_id."' AND
  229.         http_user_agent = '".$_SERVER["HTTP_USER_AGENT"]."' AND
  230.         session_expire > '".time()."'
  231.     ");
  232.     
  233.     // if anything was found
  234.     if (is_resource($result) && @mysql_num_rows($result) > 0) {
  235.       // return found data
  236.       $fields = @mysql_fetch_assoc($result);
  237.       // don't bother with the unserialization - PHP handles this automatically
  238.       return $fields["session_data"];
  239.       
  240.     }
  241.     
  242.     // if there was an error return an empty string - this HAS to be an empty string
  243.     return "";
  244.     
  245.   }
  246.   
  247.   /**
  248.    * Custom write() function
  249.    *
  250.    * @access private
  251.    */
  252.   function write($session_id, $session_data)
  253.   {
  254.   
  255.     // first checks if there is a session with this id
  256.     $result = @mysql_query("
  257.       SELECT
  258.         *
  259.       FROM
  260.         session_data
  261.       WHERE
  262.         session_id = '".$session_id."'
  263.     ");
  264.     
  265.     // if there is
  266.     if (@mysql_num_rows($result) > 0) {
  267.       // update the existing session's data
  268.       // and set new expiry time
  269.       $result = @mysql_query("
  270.         UPDATE
  271.           session_data
  272.         SET
  273.           session_data = '".$session_data."',
  274.           session_expire = '".(time() + $this->sessionLifetime)."'
  275.         WHERE
  276.           session_id = '".$session_id."'
  277.       ");
  278.       
  279.       // if anything happened
  280.       if (@mysql_affected_rows()) {
  281.       
  282.         // return true
  283.         return true;
  284.         
  285.       }
  286.     // if this session id is not in the database
  287.     } else {
  288.       // insert a new record
  289.       $result = @mysql_query("
  290.         INSERT INTO
  291.           session_data
  292.             (
  293.               session_id,
  294.               http_user_agent,
  295.               session_data,
  296.               session_expire
  297.             )
  298.           VALUES
  299.             (
  300.               '".$session_id."',
  301.               '".$_SERVER["HTTP_USER_AGENT"]."',
  302.               '".$session_data."',
  303.               '".(time() + $this->sessionLifetime)."'
  304.             )
  305.       ");
  306.       
  307.       // if anything happened
  308.       if (@mysql_affected_rows()) {
  309.       
  310.         // return an empty string
  311.         return "";
  312.         
  313.       }
  314.       
  315.     }
  316.     
  317.     // if something went wrong, return false
  318.     return false;
  319.     
  320.   }
  321.   
  322.   /**
  323.    * Custom destroy() function
  324.    *
  325.    * @access private
  326.    */
  327.   function destroy($session_id)
  328.   {
  329.     // deletes the current session id from the database
  330.     $result = @mysql_query("
  331.       DELETE FROM
  332.         session_data
  333.       WHERE
  334.         session_id = '".$session_id."'
  335.     ");
  336.     
  337.     // if anything happened
  338.     if (@mysql_affected_rows()) {
  339.     
  340.       // return true
  341.       return true;
  342.       
  343.     }
  344.     // if something went wrong, return false
  345.     return false;
  346.     
  347.   }
  348.   
  349.   /**
  350.    * Custom gc() function (garbage collector)
  351.    *
  352.    * @access private
  353.    */
  354.   function gc($maxlifetime)
  355.   {
  356.   
  357.     // it deletes expired sessions from database
  358.     $result = @mysql_query("
  359.       DELETE FROM
  360.         session_data
  361.       WHERE
  362.         session_expire < '".(time() - $maxlifetime)."'
  363.     ");
  364.     
  365.   }
  366.   
  367. }
  368. ?>

Post Information

  • Total Posts in this topic: 2 posts
  • Users browsing this forum: No registered users and 73 guests
  • You cannot post new topics in this forum
  • You cannot reply to topics in this forum
  • You cannot edit your posts in this forum
  • You cannot delete your posts in this forum
  • You cannot post attachments in this forum
 
 

© 1998-2014. Ozzu® is a registered trademark of Unmelted, LLC.