Protect PHP against session ID injection (session hijacking and session fixation)

Published on 01.05.2010, by Lubos Dzurik

Vulnerability of PHP session is often an issue. Apart from other security measurements, there are few ways to increase security of PHP application in an easy way. This article explains how you can protect against stealing your session ID from one computer and inject it into request from another computer.

Short note:
What I refer to as "cross site session ID injection" is commonly known as session hijacking and session fixation. I refer to both techniques under the same term because they both similarly attempt to steal session identifier from one computer and transfer it onto another with abusive intention. This article attempts to solve both security issues in a single step so there's no need to distinguish between the two terms.

Session IDs are transferred via server's super global array $_COOKIES and inserted into request headers with each request between client and server. There are many ways how to find ID of your current session - e.g. via network sniffer tools (e.g. Wireshark) or via Firebug.

Identifying session ID via cookie in request header
Fig. 1 - Identifying session ID via cookie sniffing tool (Firebug)

By reading this session ID and forcing it into request header from other computer (or attaching via GET request to URL), anybody can potentially get access to whatever you are doing on the web - e.g. to your bank account, personal details etc. Protecting against cross site session ID injection is one of the most basic preventions from hacking your site.

So - how to start session and minimize possibility of stealing your current session ID?

STEP 1 - Select dependable environmental variables

Collect selected environmental variables dependant onto requesting client browser. These variables are collected in superglobal arrays $_SERVER and $_ENV. You can get full list of available variables via throwing phpinfo() command or read here in details about PHP predefined variables.

Usually I choose following:

$_SERVER['REMOTE_ADDR']
e.g. 192.168.1.20
$_SERVER['HTTP_USER_AGENT']
e.g. Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727)

Variables above do exist in both - IIS and Apache (httpd). In order to limit validity of the session, we can also collect the date valid for actual day:

date('d.m.Y')
e.g. '31.12.2010'

From selected variables above we will calculate simple hash string which we will use for generating session_id. Session ID is a unique random string automatically generated by PHP. Once we decide what values shall be included into session ID hash, we can collect all values into array:

	$var[] = $_SERVER['REMOTE_ADDR'];
	$var[] = $_SERVER['HTTP_USER_AGENT'];
	$var[] = date('d.m.Y');

STEP 2 - Calculate hash for session name

From collected variables we can calculate simple hash:

	$hash = md5(implode('+',$var));

STEP 3 - Initiate the session

Once hash specific for current client calculated, we can set it as the name of current session:

	session_id = $hash;
	session_start();

Complete snippet:

	// collect highly dependale environmental variables
	$var = array();
	$var[] = $_SERVER['REMOTE_ADDR'];
	$var[] = $_SERVER['HTTP_USER_AGENT'];
	// limit session validity until midnight
	$var[] = date('d.m.Y');
	// calculate hash
	$hash = md5(implode('+',$var));
	// set session name from calculated hash
	session_id = 'MySessId'.substr($hash, 0, 5);
	// start session
	session_start();
    ...
TIP:
Similarly, you can use calculated hash for session_name instead of session_id.

Summary

This is a very simple way with negligible performance overhead to minimize risk of injecting your session ID by another user. If such a attacker would use your session ID from another computer, he would most likely use different version of browser or different IP access address and thus your server will automatically start new session for him and will not interact with your session.

Of course, I will not argue, that risk will be eliminated completely, it will only get reduced significantly. If the attacker is able to use browser with exactly the same signature (same version, operating system etc), inject calculated headers, or if he is able to use your computer as proxy gateway - then this approach won't be much at help. The purpose of this article was to introduce a good programming practice for any serious PHP web application.


Comments...

McSquirrel

01.11.2011 22:38
# 1 Reply to McSquirrel    
 

I would advice against using this technique to secure your site. IP address based validation is not a viable option in this age of mobile computing. The tried and true technique is using HTTPS with secure cookies that are only authorized on specific sub-domains that you fully control. If you're exposed to a man in the middle attack, it's already too late!

lubos

02.11.2011 00:28
# 2 Reply to lubos    
 

McSquirrel wrote on 01.11.2011 22:38:
I would advice against using this technique to secure your site. IP address based validation is not a viable option in this age of mobile computing. The tried and true technique is using HTTPS with secure cookies that are only authorized on specific sub-domains that you fully control. If you're exposed to a man in the middle attack, it's already too late!

I agree that this technique is not really 100% secure. It's purpose is to suggest how to increase the security rather than do nothing. In real world - how many common websites would install trusted SSL certificate? Chances that attacker will use (fake) the same IP address (and other client's properties used to calculate the sessionId hash) are extremly low, aren't they?

Leave your comment..
Email will be converted into something like [michael AT gmail DOT com]
Note: Offensive and unrelated comments will be deleted.
Please enter result from the picture above.