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: 947
  • View blog
  • Posts: 2,355
  • 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: 428
  • 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: 947
  • View blog
  • Posts: 2,355
  • Joined: 15-February 11

Posted 25 June 2011 - 05:30 AM

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

#4 supritshah1289  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 02-December 08

Posted 04 April 2013 - 09:11 AM

View Postcodeprada, on 25 June 2011 - 05:30 AM, said:

I'm glad you liked it :rolleyes:/>


It's a pretty good tutorial how to create login form and all. I would like to know more about it how to create database for for the users Id's and passwords more over also how to link that page with sign in page.

Thank you.

View Postcodeprada, on 25 June 2011 - 05:30 AM, said:

I'm glad you liked it :rolleyes:/>

Also that GO button to sign in the webpage.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1