Hey,

Voor het inloggen op mijn site maak ik gebruik van een PHP session.
Als de variabele $_SESSION['usr_userid'] is ingesteld, ben je ingelogd en heb je dus toegang tot extra pagina's.
Hoe veilig is zo'n systeem? Is het makkelijk te kraken en hoe zou ik het veiliger kunnen maken?
Graag wat tips.

Bedankt!
Als je gebruik maakt van 'sessies' wordt op de pc van de bezoeker een cookie opgeslagen met hierin zijn SESSION_ID. Elke keer als de bezoeker een nieuwe pagina aanvraagt op jou domein, dan wordt deze cookie meegestuurd zodat jij de bezoeker opnieuw kunt identificeren.

Het gevaar ligt er in dat iemand de SESSION_ID mogelijk kan kopieren, en in aan zijn eigen browser kan toevoegen als cookie. Wanneer deze persoon nu naar jou website gaat, denkt PHP dat het dezelfde bezoeker betreft, omdat deze alleen de SESSION_ID als referentie heeft.

Deze 'feature' noemen we 'session hijacking'.

Wat te doen:
Wat ik standaard doe is o.a. het IP adres & user agent van de gebruiker koppelen aan de betreffende sessie. Wanneer óf het IP, óf de user agent veranderd, reset ik de sessie. Nadeel van deze aanpak is dat iemand met een wisselend IP adres mogelijk opnieuw moet inloggen.



Hier wat PHP code die je inspiratie kan bieden:
<?php

	// Define urls & paths
	define('ROOT_URL', 'http://www.domainname.tld/';
	define('ROOT_PATH', dirname(__FILE__) . '/');
	define('SESSION_PATH', ROOT_PATH . 'sessions/');

	// Update session path
	session_save_path(SESSION_PATH);


	// Validate & start session
	function __session_start()
	{
		$sSessionId = __session_start_id();

		session_id($sSessionId);
		session_start();

		// Validate session
		if(isset($_SESSION['session']))
		{
			if($_SESSION['session']['REMOTE_ADDR'] && (strcmp($_SESSION['session']['REMOTE_ADDR'], $_SERVER['REMOTE_ADDR']) !== 0)) // IP has changed during session
			{
				session_write_close();
				$sSessionId = __session_start_id(false); // Force a new ID

				session_id($sSessionId);
				session_start();

				$_SESSION['session'] = array();
				$_SESSION['session']['ROOT_URL'] = ROOT_URL;
				$_SESSION['session']['REMOTE_ADDR'] = false; // No IP/SESSION lock
				$_SESSION['session']['HTTP_USER_AGENT'] = (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
				$_SESSION['session']['HTTP_X_FORWARDED_FOR'] = (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : '');

				die('<p>Your IP has changed during your session! As a protection against <a href="http://en.wikipedia.org/wiki/Session_hijacking" target="_blank">session hijacking</a> your session data is erased!</p><p>Your session is no longer chained to your IP, so it can support multiple IP addresses from now on.</p><p><a href="' . escapeHtml(ROOT_URL) . '">Please continue</a></p>');
			}
			elseif((isset($_GET['core']['session']) && (strcasecmp($_GET['core']['session'], 'reset') === 0)) || (strcmp($_SESSION['session']['ROOT_URL'], ROOT_URL) !== 0) || (strcmp($_SESSION['session']['HTTP_USER_AGENT'], (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '')) !== 0) || (strcmp($_SESSION['session']['HTTP_X_FORWARDED_FOR'], (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : '')) !== 0))
			{
				session_write_close();
				$sSessionId = __session_start_id(false); // Force a new ID

				session_id($sSessionId);
				session_start();

				$_SESSION['session'] = array();
				$_SESSION['session']['ROOT_URL'] = ROOT_URL;
				$_SESSION['session']['REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
				$_SESSION['session']['HTTP_USER_AGENT'] = (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
				$_SESSION['session']['HTTP_X_FORWARDED_FOR'] = (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : '');
			}
		}
		else
		{
			$_SESSION['session'] = array();
			$_SESSION['session']['ROOT_URL'] = ROOT_URL;
			$_SESSION['session']['REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
			$_SESSION['session']['HTTP_USER_AGENT'] = (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
			$_SESSION['session']['HTTP_X_FORWARDED_FOR'] = (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : '');
		}
	}

	// Lookup session id (or generate a new one)
	function __session_start_id($bRestoreSession = true)
	{
		$sSessionName = session_name();

		do
		{
			$sSessionId = randomCode(64, false, true); // Generate unique ID, hexadecimal
		}
		while(file_exists(session_save_path() . '/sess_' . $sSessionId));

		if($bRestoreSession) // Try to restore session
		{
			if(isset($_GET[$sSessionName]))
			{
				if(preg_match('/^[0-9a-fA-F]{64,64}$/', $_GET[$sSessionName]))
				{
					$sSessionId = $_GET[$sSessionName];
				}
				else
				{
					unset($_GET[$sSessionName]);
				}
			}

			if(isset($_COOKIE[$sSessionName]))
			{
				if(preg_match('/^[0-9a-fA-F]{64,64}$/', $_COOKIE[$sSessionName]))
				{
					$sSessionId = $_COOKIE[$sSessionName];
				}
				else
				{
					unset($_COOKIE[$sSessionName]);
				}
			}
		}
		else
		{
			unset($_GET[$sSessionName]);
			unset($_COOKIE[$sSessionName]);
		}

		return $sSessionId;
	}

	// Create a random code with N digits.
	function randomCode($iLength = 64, $bUserFriendly = false, $bHex = false)
	{
		if($bUserFriendly)
		{
			/*
				Some fonts use (almost) the same symbols for 'i', 'l' and 'one', same goes for 'o' and 'zero'.
				That's why we removed these characters from the characterlist (UPPERCASE + lowercase).
			*/
			if($bHex)
			{
				$aCharacters = array('a', 'b', 'c', 'd', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F', '2', '3', '4', '5', '6', '7', '8', '9');
			}
			else
			{
				$aCharacters = array('a', 'b', 'c', 'd', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7', '8', '9');
			}
		}
		else
		{
			if($bHex)
			{
				$aCharacters = array('a', 'b', 'c', 'd', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9');
			}
			else
			{
				$aCharacters = array('a', 'b', 'c', 'd', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9');
			}
		}

		$sResult = '';

		for($i = 0; $i < $iLength; $i++) // (62 ^ [$digits] mogelijke codes)
		{
			$sResult .= $aCharacters[rand(0, sizeof($aCharacters) - 1)];
		}

		return $sResult;
	}

?>
Ziet er goed uit, en compleet duidelijk!
Zijn er verder nog problemen waar ik rekening mee moet houden?
@Pholeron; bedankt, die methode gebruik ik zelf ook maar die user agent is nog een goede toevoeging :)

Reageren