Section 8.2. Exposed Session Data


8.2. Exposed Session Data

Even when you take care to protect your source code, your session data might be at risk. By default, PHP stores session data in /tmp. This is convenient for a number of reasons, one of which is the fact that /tmp is writable by all users, so Apache has permission to write session data there. While other users can't read these session files directly from the shell, they can write a simple script that can do the reading for them:

     <?php     header('Content-Type: text/plain');     session_start();     $path = ini_get('session.save_path');     $handle = dir($path);     while ($filename = $handle->read())     {       if (substr($filename, 0, 5) == 'sess_')       {         $data = file_get_contents("$path/$filename");         if (!empty($data))         {           session_decode($data);           $session = $_SESSION;           $_SESSION = array();           echo "Session [" . substr($filename, 5) . "]\n";           print_r($session);           echo "\n--\n\n";         }       }     }     ?> 

This script searches session.save_path for files that begin with sess_. When such a file is found, the contents are parsed and displayed with print_r( ). This makes it easy for another developer to view the session data of your users.

The best solution to this particular problem is to store your session data in a database protected with a username and password. Because access to a database is controlled, this adds an extra layer of protection. By applying the technique discussed in the previous section, the database can be used as a safehaven for your sensitive data, although you should remain alert to the fact that the security of your database becomes even more important.

To store session data in the database, you first need to create a table for it:

     CREATE TABLE sessions     (       id varchar(32) NOT NULL,       access int(10) unsigned,       data text,       PRIMARY KEY (id)     ); 

If you are using MySQL, DESCRIBE sessions provides this visual representation:

     mysql> DESCRIBE sessions;     +--------+------------------+------+-----+---------+-------+     | Field  | Type             | Null | Key | Default | Extra |     +--------+------------------+------+-----+---------+-------+     | id     | varchar(32)      |      | PRI |         |       |     | access | int(10) unsigned | YES  |     | NULL    |       |     | data   | text             | YES  |     | NULL    |       |     +--------+------------------+------+-----+---------+-------+ 

To have session data stored in this table, you need to modify PHP's native session mechanism with the session_set_save_handler( ) function:

     <?php     session_set_save_handler('_open',                              '_close',                              '_read',                              '_write',                              '_destroy',                              '_clean');     ?> 

Each of these six arguments is the name of a function that you must write. These functions handle the following tasks:

  1. Open the session data store.

  2. Close the session data store.

  3. Read session data.

  4. Write session data.

  5. Destroy session data.

  6. Clean out stale session data.

I have used descriptive names deliberately, so that you can intuit the purpose of each. The names are arbitrary, and you might consider using a leading underscore (as shown here) or some other naming convention to help prevent naming collisions. An example of each function (using MySQL) follows:

     <?php     function _open()     {       global $_sess_db;       $db_user = $_SERVER['DB_USER'];       $db_pass = $_SERVER['DB_PASS'];       $db_host = 'localhost';       if ($_sess_db = mysql_connect($db_host, $db_user, $db_pass))       {         return mysql_select_db('sessions', $_sess_db);       }       return FALSE;     }     function _close()     {       global $_sess_db;       return mysql_close($_sess_db);     }     function _read($id)     {       global $_sess_db;       $id = mysql_real_escape_string($id);       $sql = "SELECT data               FROM   sessions               WHERE  id = '$id'";       if ($result = mysql_query($sql, $_sess_db))       {         if (mysql_num_rows($result))         {           $record = mysql_fetch_assoc($result);           return $record['data'];         }       }       return '';     }     function _write($id, $data)     {       global $_sess_db;       $access = time();       $id = mysql_real_escape_string($id);       $access = mysql_real_escape_string($access);       $data = mysql_real_escape_string($data);       $sql = "REPLACE               INTO    sessions               VALUES  ('$id', '$access', '$data')";       return mysql_query($sql, $_sess_db);     }     function _destroy($id)     {       global $_sess_db;       $id = mysql_real_escape_string($id);       $sql = "DELETE               FROM   sessions               WHERE id = '$id'";       return mysql_query($sql, $_sess_db);     }     function _clean($max)     {       global $_sess_db;       $old = time() - $max;       $old = mysql_real_escape_string($old);       $sql = "DELETE               FROM   sessions               WHERE  access < '$old'";       return mysql_query($sql, $_sess_db);     }     ?> 

You must call session_set_save_handler( ) prior to calling session_start( ), but you can define the functions themselves anywhere.

The beauty of this approach is that you don't have to modify your code or the way that you use sessions in any way. $_SESSION still exists and behaves the same, PHP still takes care of generating and propagating the session identifier, and changes made to session configuration directives still apply. All you have to do is call this one function (and create the functions to which it refers), and PHP takes care of the rest.




Essential PHP Security
Essential PHP Security
ISBN: 059600656X
EAN: 2147483647
Year: 2005
Pages: 110

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net