ZCE 5.3


Session Security

	// Session fixation: http://unsafe/?PHPSESSID=123
	// Defence: session_regenerate_id() & session.use_trans_sid = 0

	// Session hijacking: She gets the new genereated id
	// Defence: Store in session $_SERVER['HTTP_USER_AGENT']
			       (does not change between requests)

* Session fixation

When a user first encounters a page in your application that calls session_start(), a session is created for 
the user. PHP generates a random session identifier to identify the user, and then it sends a Set-Cookie 
header to the client. By default, the name of this cookie is PHPSESSID. On subsequent visits, the client 
identifies the user with the cookie, and this is how the application maintains state.

It is possible, however, to set the session identifier manually through the query string, forcing the use of a 
particular session.

	A simple attack scenario:

	1. Mallory has determined that http://unsafe/ accepts session identifiers from query strings
	2. Mallory sends Alice an e-mail: "Hey, check this out, there is a cool new account summary feature 
	on our bank, http://unsafe/?PHPSESSID=123". Mallory is trying to fixate the SID to 123
	3. Alice is interested and visits http://unsafe/?PHPSESSID=123. The usual log-on screen pops up, and
	   Alice logs on.
	4. Mallory visits http://unsafe/?PHPSESSID=123 and now has unlimited access to Alice's account.

<?php /* php.ini (unsecure) session.use_trans_sid = 1 (default 0) session.use_cookies = 0 (default 1) session.use_only_cookies = 0 (default commented) */ session_start(); if (isset($_GET['btn_submit'])) { if ($_GET['username'] == 'john') { $_SESSION['username'] = 'john'; } } echo "Logged user: " . $_SESSION['username']; /* If a user access url http://localhost/tests/php/test4.php?PHPSESSID=123' target='_blank'>http://localhost/tests/php/test4.php?PHPSESSID=123 Browser output: Logged user: john In other browser (to test as if you are an attacker) http://localhost/tests/php/test4.php?PHPSESSID=123' target='_blank'>http://localhost/tests/php/test4.php?PHPSESSID=123 Browser output: Logged user: john In this way an attacker can access john's account */ ?> <form method="GET"> Username: <input type="text" name="username" value="john"/><br /> Password: <input type="password" name="password" /><br /> <input type="submit" name="btn_submit" value="Log In"/> </form>
  Since the purpose of the attack is to gain a higher level of privilege, the points at which the attack should be blocked are clear: every time a user's access level changes, it is necessary to regenerate the session identifier. There are a few ways to prevent session fixation (do all of them):
<?php / *php.ini // tell PHP not to include the identifier in the URL session.use_trans_sid = 0 // the session ID is only accepted from a cookie session.use_only_cookies = 1 */ // Regenerate the session ID anytime the session's status changes session_start(); // If the user login is successful, regenerate the session ID if (authenticate()) { session_regenerate_id(true); // true destroy the original session }
  * Session hijacking // Defence: store the User-Agent into the session Rather than providing one of his own, an attacker may gain a user's valid session identifier. For example, suppose that a user logs in. If the session identifier is regenerated, they have a new session ID. What if an attacker discovers this new ID and attempts to use it to gain access through that user's session? It is then necessary to use other means to identify the user. One way to identify the user in addition to the session identifier is to check various request headers sent by the client. One request header that is particularly helpful and does not change between requests is the User-Agent header. Since it is unlikely that a user will change from one browser to another while using the same session.
<?php session_start(); //After a successful login attempt, store the User-Agent into the session: if (authenticate()) { session_regenerate_id(); $_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT']; }
<?php // Then, on subsequent page loads, // check to ensure that the User-Agent has not changed if ($_SESSION['user_agent'] != $_SERVER['HTTP_USER_AGENT']) { // Hijack attempt // Force user to log in again exit; }