Persistent sessions with PHP

Persistent sessions is a set of mechanisms created in php that allow authentication to persist across multiple browser sessions (ie closing down the browser). Any session variables you set in php are destroyed and cant be used in further sessions. This means annoyingly that your users must then sign into you site again. Their are some security issues you must be aware of when implementing a system like this.

Persistent sessions weakens the security of your web site, issues like it being accessed on a public computer (you could add a tick box to be remembered) or if you hold security sensitive information. Its a trade off between usability and security. You could even implement a two step security system where by for example you may trust the user to carry out certain procedures from a persistent session such as adding a item to a wish list but require full password validation for procedures such as purchasing a item from a stored credit card number or changing passwords.

When thinking about how to create a system is seems tempting enough just to store the username and password in the cookie and read them off when the user comes back to the web site and automatically log them in. This is bad very idea. A potential hacker could easily gain access to this information and replay it back to your server and gain unauthorised access.

The cookie is the only way standard way to persist data across multiple sessions. So we must store information in this cookie that will provide us with the information in the future to re authenticate the user. Clearly is a security risk so the best we can do is store information that will only be useful for a certain period of time. It would be inadvisable to provide any with permanent access this way.

In the cookie we are going to store 2 pieces of information, a hash code representing the username, we’ll call this a identifier and a key (or token) that is valid only for certain period of time and is regenerated after one use. To create a hash of the username we could do something like this:

$salt = "pAulR2";
$identifier = md5( $salt . md5($username . $salt ) );

This should be stored in your database alongside your other user details. Remember to always to use some form of ‘salt‘ when creating hash’s. This is just a string that is known only to your application and kept secret. This insures that people cant use rainbow tables or take a few educated guesses to reverse the hash.

Next we must create a key (or token), this will be like our temporary password, valid for a certain period of time. We just need a long a string that isn’t predictable. One could be generated like this:

$key = md5(uniqid(rand(), true);

Again we would need to store this in the database and associate it to the correct user along with another field recording the time span for which it is valid.

Outline Example

Ok, you’ve authenticated your users username and password and they’ve indicated that they wish to remain logged in for one week.

// This examples assumes you have already connected to a MySQL database
$salt = "pAulR2";
/*
  You must create a identifier for every user and store it in the database prior implementing this.
  $identifier = md5( $salt . md5($username . $salt ) );
*/
// retrieve the $identifier from the database, I'm going to assume its in a variable called
// $user['identifier']
$identifier = $user['identifier'];

// create a random key
$key = md5(uniqid(rand(), true);
// calculate the time in 7 days ahead for expiry date
$timeout = time() + 60 * 60 * 24 * 7;

// Set the cookie with information
setcookie('authentication', "$identifier:$key", $timeout);
// now update the database with the new information
$result = mysql_query("UPDATE `user` SET key = '$key', timeout = '$timeout'
WHERE username = '$username'");
if (!$result) {
    die('Invalid query: ' . mysql_error());
}

Right that takes care of setting the cookie but know we must authorise it when its been detected when the user comes back to the site. On the users first visit you need to implement code like the following:

$salt = "pAulR2";

if (isset($_COOKIE['authentication'])) {
    // cookie is set, lets see if its vailed and log someone in
    $clean = array();
    $mysql = array();

    $now = time();

    list($identifier, $token) = explode(':', $_COOKIE['authentication']);
    if (ctype_alnum($identifier) && ctype_alnum($token)) {
	$clean['identifier'] = $identifier;
	$clean['key'] = $key;

	$mysql['identifier'] = mysql_real_escape_string($clean['identifier']);

	$result = mysql_query("SELECT * FROM user
                                       WHERE identifier = '{$mysql['identifier']}'");
	if (mysql_num_rows($result)) {
		$record = mysql_fetch_assoc($result);
		if ($clean['key'] != $record['key']) {
			// fail because the key doesn't match
		}elseif ($now > $record['timeout']){
			// fail because the cookie has expired
		}elseif ($clean['identifier'] != md5($salt.md5($record['userID'].$salt))){
			// fail because the identifiers does not match
		}else{
			/*
                          Success everything matches, now you can process
                          your login functions. The key must be re generated
                          for the next login. But don't increase the timeout to
                          ensure that the user must login in once the time
                          period has passed.
                       */
	        }
	}
	}else {
			/* failed because the information is not in the
                            correct format in the cookie */
        }
}

And remember once you have finished with the cookie delete it!

Sources: Essential PHP Security

14 thoughts on “Persistent sessions with PHP

  1. Mark

    I believe he’s referring to the fact that the output of the MD5 hash is significantly more restricted (ie, 32 chars, 0-F) than that of the component parts ($username and $salt) thus making brute force more effective.

    In reality I still think this would be extremely strong and would not cause an issue – nobody wants to break an MD5 just to steal a relatively low-security cookie! (SSL would be used if it were serious – bank details, etc).

    Cheers
    Mark

  2. Pingback: Persistent sessions with PHP | Paul Richards

  3. baskets salomon

    Trouver un babillard pour les parents d’enfants qui ont une colostomie. Si votre enfant a une certaine condition qui a provoqu? la n?cessit? d’une colostomie, alors vous pouvez trouver un forum sp?cifique pour cela. Ils sont partout et les gens ? qui vous parlez ont ?t? l?, en passant par les m?mes choses que vous ?tes, avez-enfants qui vivent la m?me chose v?tre. Il est bon d’avoir un point de vente o? vous pouvez parler librement et d’obtenir d’excellents conseils et astuces. J’ai beaucoup appris de la babillard j’appartiens. Et quand les choses se corsent, ils sont toujours l?, plus que probable qu’ils ont ?t? l? eux-m?mes.

  4. download witcher 3

    Wow, superb blog format! How lengthy have you ever been running a
    blog for? you make running a blog glance easy. The total glance of your website is excellent, let alone the content material!

  5. www.gotogcc.com

    Current Power of e – Books – Right now, e – Books have made hundreds
    of thousands of book titles in the public domakn available to a billion people who get online daily.

    Digital content doesn’t take up much room, and there is a lot of choice on how too view
    it. As I gained experience and expertise in using the internet, from
    manmy years of studying through the medium of physical books and electronic ebooks and a four
    years university undergraduate course – gained Honours with Degree, I realised that the majority
    of ebooks being sold in the ebook estores.

Comments are closed.