Page 1 of 1

User Authentication via Two Keys & IP Address Rate Topic: ***** 2 Votes

#1 codeprada  Icon User is offline

  • Changed Man With Different Priorities
  • member icon

Reputation: 876
  • View blog
  • Posts: 2,250
  • Joined: 15-February 11

Posted 06 June 2011 - 03:39 PM

This method of authenticating users involves two keys, one stored on the client via cookies and another stored on the server via sessions.

Let's make a PHP file that will contain our function to generate keys.
<?php
//function.php
/**
 *generate_key
 *
 *generates a random key
 *
 *@return (string) random string of 64 characters 
 *
 */
function generate_key()
{
	$length = 32;
	$characters = array_merge(range(0, 9), range('a', 'z'), range('A', 'Z')); 
	shuffle($characters);
	return hash_hmac('sha256', substr(implode('', $characters), 0, $length), time());
}
?>



The function above uses array_merge to combine the arrays of character sets a - z, A - Z and 0 - 9 into one array. Shuffle is then used to rearrange the $characters array in a random order. The last line is where it may seem a bit confusing. Implode retrieves the array elements and makes a string out of them with the first parameter being the glue or basically the character that's going between each character in the string. So now we have a string of 62 characters in length. We now take the first 32 characters of that string and perform a SHA256 hash on it with a key being the current timestamp.

Now we'll make our the page for our login form.
<html>
<head>
	<title>Login</title>
</head>
<body>
	<form action="login.php" method="post" enctype="application/x-www-form-urlencoded">
		Username <input type="text" name="username" /><br />
		Password <input type="password" name="password" /><br />
		<input type="submit" value="Login" />
	</form>
</body>
</html>


This is a simple straight forward login form with a username and password field.

This is going to be our authentication page.
<?php
//login.php
session_start();
require_once("functions.php");

if(isset($_POST['username'], $_POST['password'])) //verify we've got what we need to work with
{
	/*********database_credentials.php**************/
	$mysqli = new MySQLi('localhost', 'root', '', 'test'); //change to suit your database
	if($mysqli->errno)
		//connection wasn't made
		//handle the error here
		header("location: index.html"); //we'll just redirect for now
	/************************************************/	
	
	//We don't have to work about SQL injections here 
	$stmt = $mysqli->prepare("SELECT COUNT(username) AS total FROM credentials WHERE username = ? AND password = ?");
	//if the passwords in your table are hashed then you should apply the hashing and/or salts before passing it
	//they should in fact be hashed preferably with a hashing algorithm of the SHA family
	$stmt->bind_param('ss', $_POST['username'], $_POST['password']);
	$stmt->execute();
	$stmt->bind_result($total); //place the result (total) into this variable
	$stmt->fetch(); //fill the result variable(s) binded 
	
	//close all connections
	$stmt->close();
	$mysqli->close();

	//if total is equal to 1 then that means we have a match
	if((int)$total == 1)
	{
		session_regenerate_id(true); //delete old session variables
		/*********Explained below************/
		$_SESSION['user'] = $_POST['username'];
		$key = generate_key();
		$hash = hash_hmac('sha512', $_POST['password'], $key);
		$_SESSION['key'] = $key;
		$_SESSION['auth'] = hash_hmac('sha512', $key, 
				    hash_hmac('sha512', $_SESSION['user'] . 
						(isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? 
					 	       $_SERVER['HTTP_X_FORWARDED_FOR'] : 
					               $_SERVER['REMOTE_ADDR']), $hash));
		/************************************/

		if(!setcookie('hash', $hash, 0, '/')) //login isn't possible if user's browser doesn't accept cookies
		{
			session_regenerate_id(true);
			header("location: your_login_page.php"); //original_page would be your login page
			exit();
		}
		header("location: protected_page.php");
	}
	else
	{
		//anything else we don't care about
		header("location: your_login_page.php");
	}
}
?>



Our $hash variable will be used to store the hash of the user's password with the randomly generated key in a cookie. It is important it is stored in a cookie because basically we want to calculate the hash of 2 strings/keys to get one final hash and the server and client must have one key each. If one of those keys is incorrect by even a single character the user will not have access to protected pages.
Next we store our key within a session variable for later use. Now for the most important part of authentication, $_SESSION['auth']. This hash is comprised of 4 things, $key, username, client's IP and $hash. The client's IP address is concatenated unto the username thus deriving something like this
codeprada69.68.11.127
This will be hashed with SHA512 while using $hash as the key. The hash produced from this will be used as the key to apply another SHA512 hash unto $key.
If a client is using a proxy then more times than not HTTP_X_FORWARDED_FOR will contain the client's IP instead of REMOTE_ADDR. This doesn't apply to anonymous proxies that doesn't set the value of HTTP_X_FORWARDED_FOR. The IP address is used so that if the user either changes computers but tries to re-use the same cookies (replay attack) or does anything that changes their IP the login session would not be valid.

Let's now make our checklogin.php
<?php
//checklogin.php
session_start();

//don't want to read a cookie or session variable that doesn't exist
if(isset($_COOKIE['hash'], 
		 $_SESSION['key'], 
		$_SESSION['user'])
   ) 
{
	if(strcmp($_SESSION['auth'], //remember this? 
			  hash_hmac('sha512', $_SESSION['key'], //see below for explanation 
					hash_hmac('sha512', $_SESSION['user'] .
						      (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? 
					 	            $_SERVER['HTTP_X_FORWARDED_FOR'] : 
					                    $_SERVER['REMOTE_ADDR']), 
						  $_COOKIE['hash'])
					)
			 )
		)
	{
		header("location: index.html");
	}
}
else
{
	header("location: index.html");
}
?>



We must now rebuild the keys collected from the cookies and session and verify that the final hashed string matches $_SESSION['auth']. The key is read from $_SESSION['key'] and a SHA512 hash is applied to it with a key of the string produced from a SHA512 hash of the username concatenated with the client's IP address with a key of the hash retrieved from the cookie. This should produce the exact same string as $_SESSION['auth'] if no data was tampered with or changed.

To restrict access to a page this must be placed at the top of that page.
require_once("checklogin.php");


Here's our protected page
<?php
//protected_page.php
require_once("checklogin.php");
?>
<html>
<head>
<title>Sample Page</title>
</head>

<body>
<h1>Welcome to the protected sample page.</h1>
<h2><a href="logout.php">Logout Here</a></h2>
</body>
</html>


The final piece will be our logout page of course.
<?php
//logout.php
session_start();
session_destroy();
unset($_SESSION);
setcookie("hash", "", time() - 3600);
header("location: index.html");
?>


Is This A Good Question/Topic? 3
  • +

Replies To: User Authentication via Two Keys & IP Address

#2 dangmnx  Icon User is offline

  • D.I.C Regular

Reputation: -1
  • View blog
  • Posts: 387
  • Joined: 10-April 09

Posted 24 June 2011 - 09:11 PM

Thank you very much for this!
Was This Post Helpful? 0
  • +
  • -

#3 codeprada  Icon User is offline

  • Changed Man With Different Priorities
  • member icon

Reputation: 876
  • View blog
  • Posts: 2,250
  • Joined: 15-February 11

Posted 25 June 2011 - 05:30 AM

I'm glad you liked it :rolleyes:
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1