 | Session handling
When a request is made for a Web site, it is entirely independent of every request
before it. To implement user functionality, a particular Web client needs repeated
access to a unique, possibly secret, piece of information. This is called session
handling in Web applications, and the subtleties of properly handling sessions is a headache to many developers.
Session-handling basics
The basic idea is the same across any programming language. Upon first visiting the Web
site, the client is given a unique ID, generally stored as a cookie. On the server
side, an array of variables is stored, in some way, which corresponds to that unique
ID. For any subsequent request by the same client, the unique ID is sent along with the
request, and the server loads the array into memory. These variables are called the
session variables for the client. In PHP, they are stored in the $_SESSION global variable.
You could simply use the $_SESSION global variable to access
session information when using CakePHP. However, CakePHP comes with its own
session-handling object, which, as we will see later, has a number of benefits.
Session handling within Tor
You have already implemented sessions without much effort. When the user logs in, the
UsersController object stores the username and associates
it automatically with the client during subsequent requests.
Every Controller object (anything inheriting from AppController) automatically has access to the Session component.
Recall that a Component is a class associated with a
controller that allows extra functionality, much like a helper provides extra
functionality to a view. You used the Acl component in Part
2 when you added ACLs. Recall that you needed to add the following line to the
beginning of the ProductsController and UsersController classes: var $components = array('Acl');.
Though session handling is a component in CakePHP, it is a standard component included
with every controller, so there is no need to add it to this list.
To use the Session component, simply access the session instance variable in the
controller. The two most important functions of the session handler are setting and
getting variables, which are achieved by calling the read
and write methods. For user login, you used the code in
Listing 7 to write the current client's username to the session. This code is located
in the UsersController class.
Listing 7. Using the write
method to store the username
function login()
{
...
$this->Session->write('user', $this->data['User']['username']);
...
{
|
The write method takes two parameters. The first is the key
being assigned and the second is the value to assign it. In this case, the key is
user and the value is the username entered (see Listing 8).
The username is later accessed to test whether a product can be viewed or edited based on the ACL.
Listing 8. Using the read
method to access the username
function view($id) {
...
if ($this->Acl->check($this->Session->read('user'),
$id.'-'.$product['Product']['title'], 'read'))
{
...
}
}
|
The read method takes a single parameter — the
key you wish to access — and returns the value that was stored.
Storing sessions
None of this should be new to Web developers, but session handling is generally only a
simple matter for small applications. If an application requires sensitive user
information to be stored in session, such as passwords or credit card information, where and how the data is stored is vitally important.
Session storing is controlled by a single line in CakePHP: Configure::write('Session.save', 'php');. This line, located in the
/app/config/core.php file, tells Cake how sessions should be stored. There are three
valid values: php (use whatever the php.ini file says),
cake (save session files in
Cake's tmp directory), and database (use Cake's database sessions).
Storing sessions: cake
When this value is set, sessions are stored as files within your application folder.
CakePHP provides a folder at /app/tmp/session with files that look something like
sess_50bfa744a2ab2c98df808f70c893704c. Within these files, individual session variables
are stored as plain text without encryption.
The Apache Web server has a setting called safe mode that restricts the folders Apache
has access to. Generally, Apache can only read anything within the docroot of the site,
with some exceptions regarding library files. In this series, you have installed
CakePHP by dropping the entire directory into Apache's DocumentRoot directory (in this
case, the /webroot directory). That's certainly an easy way to install the framework,
but it's not the most secure, and this is one reason why. By setting session handling
to cake, you are storing session variables in a
directory that could be accessed directly by the browser. If your site is compromised
in such a way that an attacker can cause Apache to return arbitrary files, every user's
session data will be vulnerable (though that might be the least of your worries). Cake
does a pretty good job of protecting these files even if everything is in the
DocumentRoot, but ideally, you should install more securely by making the app/webroot
directory your DocumentRoot directory. This would keep the Cake session files offline.
It is important to note that you cannot control the permissions on these session files.
They will have the exact same user and group permissions PHP was granted. On some
systems, this may be a security vulnerability, as well.
Advantages:
- Session variables are stored within Cake, and, thus, the entire application stays in one place.
- Session files can be read with a text browser, possibly for debugging (unlikely useful).
- Starting and accessing a session do not require a database connection (unlikely
helpful, since accessing models in CakePHP initiates a PHP session).
Disadvantages:
- Any files stored in DocumentRoot can be compromised if the Web server is compromised.
- Session files have the same permissions PHP is given.
- Load-balanced Web servers not sharing a file system cannot share access to session
files, causing sessions to be mysteriously dropped unless using sticky sessions.
Storing sessions: database
If the session information you are storing needs a higher level of security or a
greater control over permissions, database sessions are better. By setting Session_save to database, you're telling
CakePHP to store all serialized variable information on a table in the database with the rest of your application.
Before you can use database sessions with CakePHP, you must create the table. Feel free
to give it a try with Tor. By default, the name of the table is cake_sessions,
although this can be changed in the file app/config/core.php. You will need to
uncomment the Configure::write lines for Session.table and
Session.database in order to use database session storage. The schema for this table is
stored in app/config/sql/sessions.sql. The schema included with CakePHP V1.2.0.x is
shown below.
Listing 9. Create table cake_sessions
CREATE TABLE cake_sessions (
id varchar(255) NOT NULL default '',
data text,
expires int(11) default NULL,
PRIMARY KEY (id)
);
|
After you've created the table and set the Session.save to
database, try logging into Tor at /users/login. After you
log in, check the database to see if your session appeared. There should be a single row that looks something like this:
id data expires
50bfa744a2ab2c98df808f70c893704c Config|a:3:{s:4:"rand";i:94427... 1164661678
|
Storing sessions in the database directly addresses all three disadvantages listed in the method above.
First, Apache generally has no direct access to the database, so compromising the Web
server doesn't expose the session files. Second, permissions on the database can be
explicitly set for your application, and you can even restrict access to a particular
host. Third, load-balanced servers have shared access to the session table with no extra work on your part.
For most large applications, database sessions are essential because they allow the
greatest amount of security with the least amount of effort.
Advantages:
- Simple to set up — only requires one extra table in your database.
- A loss of security in the Web server will probably not result in sessions being compromised.
- Sessions can be more easily shared across load-balanced servers.
Disadvantages:
- Using the database to store sessions adds some database overhead. That can add up.
- Sessions are still stored in plain text on the database; database backups may
cause sensitive data to be stored for prolonged periods of time.
- Depending on how your database is set up, communications between your application
and the database may not be secure. If your database isn't on localhost, or isn't
over a secure channel, such as a VPN, it is possible that the communications can become compromised.
Storing sessions: php
The final method for storing sessions is to use whatever session handling PHP is set up
to use. By default, PHP will write its sessions as files similar to the cake setting for Session.save. One main
difference is that instead of saving session variables within the Cake application,
they are generally stored in a temporary directory elsewhere on the file system. This
may or may not be preferable to having sessions stored in the same directory as your site.
By setting sessions to be stored via PHP, you are giving more control over sessions to
PHP, rather than to Cake. PHP allows you to override a number of session-handler
functions, essentially overriding the way sessions are stored in a method of your
choosing. That could be storing sessions in a separate database, over a custom secure
channel, or whatever crazy method you can come up with.
If you need to change the way session handling is done in PHP, there is a single
function, session_set_save_handler, that controls the
session-callback function. Passing this function the names of function that open,
close, read, and write to the session is demonstrated below. An in-depth discussion of
the session_set_save_handler function is outside the scope
of this article (see Resources).
Listing 10. Redefining how PHP stores sessions
function open($save_path, $session_name)
{
global $sess_save_path;
$sess_save_path = $save_path;
return(true);
}
function read($id)
{
global $sess_save_path;
$sess_file = "$sess_save_path/sess_$id";
return (string) @file_get_contents($sess_file);
}
...
session_set_save_handler("open", "close", "read", "write", "destroy", "gc");
|
The session-handling functions are redefined by the PHP functions: session_start(). Using this method has some advantages.
Advantages:
- It's flexible. Any storage method supported by PHP.
- If you don't override the session-handling functions, sessions will be stored the
same way as all the other applications on your server.
Disadvantage:
- Since PHP is set up to store sessions in the tmp directory by default, you
could face some of the same disadvantages described above in "Storing sessions:
'cake'."
Deciding what method to use for handling session storage isn't always cut and dry.
Most of the time, letting PHP handle your sessions will be fine. But ultimately, you
will need to make that decision based on the particulars of your application.
In the next section, we discuss the Request Handler component and how you can use it to
add Ajax functionality to your application.
|  |