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.127This 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");
?>





MultiQuote






|