What are some guidelines for maintaining responsible session security with PHP? There's information all over the web, so it's about time it all landed in one place!
One guideline is to call session_regenerate_id every time a session's security level changes. This helps prevent session hijacking.
I think one of the major problems (which is being addressed in PHP 6) is register_globals. Right now one of the standard methods used to avoid register_globals is to use the $_REQUEST, $_GET or $_POST arrays.
The "correct" way to do it (as of 5.2, although it's a little buggy there, but stable as of 6, which is coming soon) is through filters.
So instead of:
$username = $_POST["username"];
you would do:
$username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);
or even just:
$username = filter_input(INPUT_POST, 'username');
This is pretty trivial and obvious, but be sure to session_destroy after every use. This can be difficult to implement if the user does not log out explicitly, so a timer can be set to do this.
Here is a good tutorial on setTimer() and clearTimer().
The main problem with PHP sessions and security (besides session hijacking) comes with what environment you are in. By default PHP stores the session data in a file in the OS's temp directory. Without any special thought or planning this is a world readable directory so all of your session information is public to anyone with access to the server.
As for maintaining sessions over multiple servers. At that point it would be better to switch PHP to user handled sessions where it calls your provided functions to CRUD (create, read, update, delete) the session data. At that point you could store the session information in a database or memcache like solution so that all application servers have access to the data.
Storing your own sessions may also be advantageous if you are on a shared server because it will let you store it in the database which you often times have more control over then the filesystem.
I would check both IP and User Agent to see if they change
if ($_SESSION['user_agent'] != $_SERVER['HTTP_USER_AGENT']
|| $_SESSION['user_ip'] != $_SERVER['REMOTE_ADDR'])
{
//Something fishy is going on here?
}
Using IP address isn't really the best idea in my experience. For example; my office has two IP addresses that get used depending on load and we constantly run into issues using IP addresses.
Instead, I've opted for storing the sessions in a separate database for the domains on my servers. This way no one on the file system has access to that session info. This was really helpful with phpBB before 3.0 (they've since fixed this) but it's still a good idea I think.
If you you use session_set_save_handler() you can set your own session handler. For example you could store your sessions in the database. Refer to the php.net comments for examples of a database session handler.
DB sessions are also good if you have multiple servers otherwise if you are using file based sessions you would need to make sure that each webserver had access to the same filesystem to read/write the sessions.
There is a couple of things todo in order to keep your session secure:
- Use SSL when authenticating users or performing sensitive operations.
- Regenerate the session id whenever the security level changes (such as logging in). You can even regenerate the session id every request if you wish.
- Have sessions timeout
- Don't use register globals
- Store authentication details on the server. That is don't send details such as username in the cookie.
- Check the
$_SERVER['HTTP_USER_AGENT']
. This adds a small barrier to session hijacking. You can also check the IP address. But this causes problems for users that have changing IP address due to load balancing on multiple internet connections etc (which is the case in our environment here). - Lock down access to the sessions on the file system or use custom session handling
- For sensitive operations consider requiring the user to provide their authenication details
This session fixation paper has very good pointers where attack may come. See also session fixation page at Wikipedia.
My two (or more) cents:
- Trust no one
- Filter input, escape output (cookie, session data are your input too)
- Avoid XSS (keep your HTML well formed, take a look at PHPTAL or HTMLPurifier)
- Defense in depth
- Do not expose data
There is a tiny but good book on this topic: Essential PHP Security by Chris Shiflett.
On the home page of the book you will find some interesting code examples and sample chapters.
You may use technique mentioned above (IP & UserAgent), described here: How to avoid identity theft