Secure session management

Discussions of secure PHP coding. Security in software is important, so don't be afraid to ask. And when answering: be anal. Nitpick. No security vulnerability is too small.

Moderator: General Moderators

Post Reply
superfane
Forum Newbie
Posts: 2
Joined: Sat Apr 23, 2005 1:56 pm

Secure session management

Post by superfane »

Hello,

First of all, please excuse my poor english! I need some help for making a (relatively) secure session management class and a system to authenticate users. I know that they are lots of ready-made scripts out there, but I need to make this one all by myself. I also know that little knowledge is worst than not knowing anything, but I still need to make this script, even if I don't really know very much about security in PHP. This is why I need your help.
I've written a piece of code for managing session and store them in a mysql database. I've tried to avoid all the problems that may appear by session hijacking or session fixation but... I need some advices from the experts :).
I've bored you enought with my talking, so let's see the code:

Code: Select all

<?php

// Author: Stefan Vaduva
// Website: http://www.vamist.com
// Thanks to Matt Wade for this tutorial: http://www.zend.com/zend/spotlight/code ... -wade8.php
// If you use this piece of code, please do not remove this header

	require_once('settings.php');
	class session_manager
	{
		private $sql;
		function __construct()
		{
			session_set_save_handler
			(
				array(&$this, 'open'), 
				array(&$this, 'close'), 
				array(&$this, 'read'), 
				array(&$this, 'write'), 
				array(&$this, 'destroy'), 
				array(&$this, 'gc')
			);
			session_regenerate_id(); //this is to avoid session fixation
			session_start();
		}
		function open($ses_path, $ses_name)
		{
			$this -> sql = new mysqli(settings::$sql_host, settings::$sql_user, settings::$sql_pass, settings::$sql_db);
			if(mysqli_connect_error())
			{
				echo mysqli_connect_error();
				return FALSE;
			}
			else
			{
				return TRUE;
			}
		}
		function close()
		{
			$this -> gc(0);
			$this -> sql -> close();
			return TRUE;
		}
		function read($ses_id)
		{
			$result = $this -> sql -> query(&quote;SELECT * FROM &quote;.settings::$ses_table.&quote; WHERE ses_id = '$ses_id'&quote;);
			if((!$this -> sql -> error) && ($result))
			{
				$row = $result -> fetch_assoc();
				if($rowї'ses_owner'] != $_SERVERї'REMOTE_ADDR']) //this to avoid session hijacking (return the session value only if the request is made from the computer that started the session)
				{
					return '';
				}
				else
				{
					return $rowї'ses_value'];
				}
			}
			else
			{
				return '';
			}
		}
		private function success_query($result) //check if the query was successfully
		{
			if((!$this -> sql -> error) && ($result))
			{
				return TRUE;
			}	
			else
			{
				return FALSE;
			}
		}
		function write($ses_id, $ses_value)
		{
			$ses_value = $this -> sql -> real_escape_string($ses_value);
			$result = $this -> sql -> query(&quote;INSERT INTO &quote;.settings::$ses_table.&quote; (ses_id, ses_time, ses_start, ses_value, ses_owner) VALUES ('$ses_id', '&quote;.time().&quote;', '&quote;.time().&quote;', '$ses_value', '&quote;.$_SERVERї'REMOTE_ADDR'].&quote;')&quote;);
			$err = $this -> sql -> errno;
			if((($err == 1062) || ($err == 1022)) && (!$result))
			{
				$result = $this -> sql -> query(&quote;UPDATE &quote;.settings::$ses_table.&quote; SET ses_time = '&quote;.time().&quote;', ses_value = '$ses_value' WHERE ses_id = '$ses_id' AND ses_owner = '&quote;.$_SERVERї'REMOTE_ADDR'].&quote;'&quote;);
				return $this -> success_query($result);
			}
			else
			{
				return TRUE;
			}
		}
		function destroy($ses_id)
		{
			$result = $this -> sql -> query(&quote;DELETE FROM &quote;.settings::$ses_table.&quote; WHERE ses_id = '$ses_id'&quote;);
			return $this -> success_query($result);
		}
		function gc($ses_life)
		{
			$result = $this -> sql -> query(&quote;DELETE FROM &quote;.settings::$ses_table.&quote; WHERE ses_time < &quote;.strtotime('-'.settings::$ses_life.' minutes'));
			return $this -> success_query($result);
		}
	}
?>
If anyone of you has patience, I will dare to ask you to analize my code and tell me if an atacker can still get unauthorized access to my website by using session hijacking technique, session fixation or any other technique. I know that some users can't get access to my website if they have an IP that is changing with every request, but now I don't care about that.
Sorry for the lenght of this post and I hope that I don't upset anybody with this thread.

Thanks,
Stefan
superfane
Forum Newbie
Posts: 2
Joined: Sat Apr 23, 2005 1:56 pm

Post by superfane »

Just a little correction... The correct code will be:

Code: Select all

session_start();
            session_regenerate_id(); //this is to avoid session fixation
and NOT:

Code: Select all

session_regenerate_id(); //this is to avoid session fixation
            session_start();
ody
Forum Contributor
Posts: 147
Joined: Sat Mar 27, 2004 4:42 am
Location: ManchesterUK

Post by ody »

I never thought to stick the session init code into the contruct, nice one! thanks that just cleaned things up for me a little!
timvw
DevNet Master
Posts: 4897
Joined: Mon Jan 19, 2004 11:11 pm
Location: Leuven, Belgium

Post by timvw »

i would only regenerate the session_id if the access rights to a website change...
sumeet
Forum Newbie
Posts: 15
Joined: Mon May 23, 2005 3:55 pm
Location: Hyderabad
Contact:

Post by sumeet »

superfane wrote:Just a little correction... The correct code will be:

Code: Select all

session_start();
            session_regenerate_id(); //this is to avoid session fixation
and NOT:

Code: Select all

session_regenerate_id(); //this is to avoid session fixation
            session_start();
I wud advice u to generate session id by urself ... dont rely on the one generated by php ... it will give trouble in tabs .. as it assigns same session id to diff logins in diff tabs in firefox
Post Reply