Article
The PHP Anthology Volume 2, Chapter 1 - Access Control
How do I authenticate users with sessions?
Sessions are a mechanism that allows PHP to preserve state between executions. In simple terms, sessions allow you to store variables from one page and use them on another. So if a visitor tells you his name is "Bob" (via a form) on one page, sessions will help you remember his name and allow you to, for instance, place on all the other pages of your site personal messages such as, "Where would you like to go today, Bob?" (don't be surprised if Bob leaves pretty quickly, though).
The basic mechanism of sessions works like this: first, PHP generates a unique, thirty-two character string to identify the session. It then passes the value to the browser; simultaneously, it creates a file on the server and includes the session ID in the filename. There are two methods by which PHP can inform a browser of its session ID: by adding the ID to the query string of all relative links on the page, or by sending it as a cookie. Within the file that's stored on the server, PHP saves the names and values of the variables it has been told to store for the session.
When the browser makes a request for another page, it tells PHP which session it was assigned via the URL query string, or by returning the cookie. PHP then looks up the file it created when the session was started, and so has access to the data stored within the session.
Once the session has been established, it will continue until it is specifically destroyed by PHP (in response to a user clicking "Log out," for example), or the session has been inactive for longer than a given period of time (24 minutes by default), at which point it becomes flagged for garbage collection and will be deleted the next time PHP checks for outdated sessions.
The following HTTP response headers show a server passing a session cookie to a browser, as a result of the session_start function in a PHP script:
HTTP/1.1 200 OK
Date: Wed, 26 Feb 2003 02:23:08 GMT
Server: Apache/1.3.27 (Unix) PHP/4.3.1
X-Powered-By: PHP/4.3.1
Set-Cookie: PHPSESSID=ce558537fb4aefe349bb8d48c5dcc6d3; path=/
Connection: close
Content-Type: text/html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
…
Note that I've said sessions are stored on the server as files. It's also possible to store sessions using other means, such as a database or even shared memory. This can be useful for displaying "Who is Online" type information as well as load balancing multiple Web servers using a single session repository, allowing visitors to (unknowingly) swap servers while maintaining their session.
Session Security
Sessions are very useful, but there are some important security considerations you should take into account when using them in your applications:
- By default, all a browser has to do to gain control of a session is pass a valid session ID to PHP. In an ideal world, you could store the IP address that registered the session, and double check it on every new request that used the associated session ID. Unfortunately, some ISPs, such as AOL, assign their users a new IP on almost every page request, so this type of security mechanism would soon start throwing valid users out of the system. As such, it's important to design your application in a manner that assumes that one of your users will eventually have his or her session "hijacked." The user's account is only exposed as long as the session hasn't expired, so your focus should be on preventing the hijackers from doing serious damage while they're in the system. This means, for example, that for logged-in users to change their accounts' passwords, they should be asked to provide their old passwords—obviously, hijackers won't know these. Also, be careful with the personal information you make available to users (such as credit card details), and if you give users the opportunity to make significant changes to their accounts, for instance, changing a shipping address, be sure to send a summary notification to their email address (this will alert users whose sessions have been hijacked).
To keep the session ID completely hidden, you'll need to use SSL to encrypt the conversation. What's more, you should only use the cookie method of passing the session ID. If you pass it in the URL, you may give away the session ID upon referring the visitor to another site, thanks to the
referrerheader in the HTTP request. - The files PHP creates for the purpose of storing session information are, by default, stored in the temporary directory of the operating system under which PHP is running. On Unix based systems such as Linux, this will be
/tmp. And, if you're on a shared server, this will mean that other users on the server can read the files' contents. They may not be able to identify which virtual host and PHP script are the owners of the session but, depending on the information you place there, they may be able to guess. This is a serious cause for concern on shared PHP systems; the most effective solution is to store your sessions in a database, rather than the server's temporary directory. We'll look more closely at custom session handlers later in this chapter, but a partial solution is to set thesession.save_pathoption to a directory that's not available to the public. You'll need to contact your hosting company in order to have set the correct permissions for that directory, so that the 'nobody' or 'wwwuser' user with which PHP runs has access to read, write, and delete files in that directory. Session IDs and Cross-Site Scripting One final warning: using a common Web security exploit, cross-site scripting (XSS), it's possible for an attacker to place JavaScript on your site that will cause visitors to give away their session ID to a remote Website, thereby allowing their sessions to be hijacked. If you allow your visitors to post any HTML, make sure you check and validate it very carefully (see Appendix C, Security Checklist for more on XSS and Chapter 5, Text Manipulation for an HTML filtering mechanism). Remember the golden rules: never rely on client side technologies (such as JavaScript) to handle security and never trust anything you get from a browser.
Getting Started
I hope that introduction hasn't made you so paranoid about using sessions that you'll never touch them. In general, sessions offer a mechanism that is both simple to use and powerful—it's an essential tool for building online applications.
The first development trick you need to know is that you should always access session variables using their predefined global variable $_SESSION, not the functions session_register and session_unregister. These functions fail to work correctly when PHP's register_globals setting has been disabled, which is the way you should be programming with PHP (see Appendix A, PHP Configuration for details).
To start off slowly, here's a simple example of how sessions can be used:
Example 1.3. 3.php
<?php
session_start();
// If session variable doesn't exist, register it
if (!isset($_SESSION['test'])) {
$_SESSION['test'] = 'Hello World!';
echo '$_SESSION[\'test\'] is registered.<br />' .
'Please refresh page';
} else {
// It's registered so display it
echo '$_SESSION[\'test\'] = ' . $_SESSION['test'];
}
?>
The first order of business in a script that uses sessions is to call session_start to load any existing session variables.
This script registers the session variable the first time the page is displayed. The next time (and all times thereafter, until the session times out through inactivity), the script will display the value of the session variable.
That's a simple example of how sessions can be used. We'll use them to store the value of a user name and password shortly, but first, we need to put together some classes that will collaborate to deal with both sessions and authentication. Don't panic! The classes themselves may get fairly complex, but using them from an external script will be easy.