Post: [TUT] Secure Login w/ PHP & AJAX
05-10-2011, 01:13 AM #1
(adsbygoogle = window.adsbygoogle || []).push({});
Originally posted by 039

I came across a login method a few days ago and i decided to implement it. I cannot explain everything since it'll make this tutorial into a book and I'd have to post this thread in the sellers section....blushing Don't be afraid to ask questions.

Live Demo => [url=https://*******/Y5XD]here[/url]
You can try to get pass it if you want.

[size=large]Summary:[/size]

  1. AJAX is used to retrieve a key from the server
  2. A SHA1 hash is applied to the password
  3. Hashed password is concatenated to the key
  4. A SHA1 hash is performed one the concatenated strings to form the login hash
  5. Username, login hash and hashed password are sent to the server for verification
  6. If server's login hash matches that sent by the client then client is authenticated.


Now let's get down the code.
Our first and main page is going to be index.php. See full code below. We're going to design a simple login form with just two input fields, username and password and one hidden field to store our key. Just for the fun of it let's throw the button in there so that the user can submit the form :tongue:.


    
<form id="form1" name="form1">
<table>
<tr>
<td>Username</td>
<td><input type="text" id="username" name="username" size="30" /></td>
</tr>
<tr>
<td>Password</td>
<td><input type="password" id="password" name="password" size="30" /></td>
</tr>
</table>
<input type="hidden" id="key" name="key" />
</form>
<button id="login" disabled="disabled" onclick="login()">LOGIN</button>



Don't worry about the LOGIN button being disabled right now. It'll all be clear later on in the tutorial. The hidden field, key, will store our 32 character key when it's been received from the server. I forgot to mention that I will be using You must login or register to view this content. instead of You must login or register to view this content. but which ever one you choose is solely up to you.

Now that your have the form in place (I hope you have made a html, head and body tag) we must make our page request the key from the server upon loading. This is done using the onload() event. Make your opening body tag look like this...

    <body onload="getKey()">


Again don't worry about where the "getKey()" function is because I'll get to that. Right below your LOGIN button we are going to create a "div" so that we can see whether we've logged in or not.

    <div id="results"></div>


Below that "div" add the following code

    If you can see this page =><a href="sample_page.php"> Sample Page </a> then you've successfully registered.


A link to our test page. This page can only be accessed if we've successfully logged in.
Also to the very top of your page add

    <?php session_start() ?>


[size=medium]AJAX/JAVASCRIPT[/size]
You're going to need to save the SHA512.js to a file on your computer. The link is provided above.
In your head section add the script

    <script type="text/javascript" src="sha512.js"></script>


That file does all the hashing. Also add the code below to your head section

    
<script type="text/javascript">
document.oncontextmenu = function() { return false; } //disable right clicking
function getKey()
{
var xmlhttp;
if (window.XMLHttpRequest)
xmlhttp = new XMLHttpRequest();
else
xmlhttp = new ActiveXObject("Microsoft.XMLHTTPREQUEST");
xmlhttp.onreadystatechange = function() {
if(xmlhttp.status == 200 && xmlhttp.readyState == 4) {
var str = xmlhttp.responseText;
var expr = /^_SESSION_REGISTERED_/;
if (str.search(expr) == -1 ) {
if (str.length > 32)
//this is only because 000webhost concats a counter to the key and i only need the first 32 characters since my key is 32 chars long Smile
str = str.substr(0, 32);
document.getElementById("key").value = str;
document.getElementById("login").disabled = false;
}
else{
document.getElementById("results").innerHTML = "You are already logged in! " + "Logout <a href=\"logout.php\">Here</a>";
return;
}
}
}
xmlhttp.open("GET", "challenge.php", true);
xmlhttp.send();
}

function login()
{
var xmlhttp;
if (window.XMLHttpRequest)
xmlhttp = new XMLHttpRequest();
else
xmlhttp = new ActiveXObject("Microsoft.XMLHTTPREQUEST");

var key = document.getElementById("key").value;
var pass = hex_sha512(document.getElementById("password").value);
var auth = hex_sha512(key + pass);

xmlhttp.onreadystatechange = function() {
if(xmlhttp.status == 200 && xmlhttp.readyState == 4)
document.getElementById("results").innerHTML = xmlhttp.responseText;
}

document.getElementById("results").innerHTML = "Please wait...";
var str = "user=" + document.getElementById("username").value + "&hash=" + auth + "&pass=" + pass;
xmlhttp.open("POST", "auth.php", true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send(str);
}

</script>


The getKey() function summarized sends a request to the challenge.php file and takes the response (which can be in a string or xml format) and checks whether we're already registered. If we are the LOGIN button stays disabled and a logout link is created below. If we are not registered then it takes the first 32 characters of the response (since our key will be 32 characters long) and adds it to the hidden key in our form below for later use. The form is not allowed to be submitted until the key arrives. For users with slow internet connections ... :sleep: The key usually takes less than 1 second to arrive though so no worries there.

Don't know what the hell i just said or what the heck is XMLHTTPRequest? You must login or register to view this content.

The login() function summarized goes like this. A new XMLHTTPRequest Object is created then here comes the tricky part, the key is retrieved from our form (remember the hidden type?) and so is the password the user entered. Using the sha512.js script a hash is done on the password. After the key is concatenated to the hashed password and a hash is done on the joined string to get the "login_hash" or in this case variable "auth". Since you reached this far I'm assuming you know how the XMLHTTPRequest (wow that's long) object works. Instead of a GET method we are using a POST method to send the information to the file auth.php on the server.

Upon logging in 2 cookies will be created and the values of those cookies will be hashes. As you will see in the auth.php file. Those hash values are what I will be using to register the session.

[size=medium]CHALLENGE.PHP[/size]
    
<?php
session_start();
$validate = hash('sha512', $_COOKIE["authenticate"] . $_SESSION['key'], false);
$username = hash('sha512', $_SESSION['user'], false);
if (!session_is_registered($_COOKIE["authenticate"]) || !session_is_registered($validate) ||
!session_is_registered($username)) {
$charset = array('A','B','C','Awesome face','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S',
'T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r',
's','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9'Winky Winky;
$key = "";
$c = 0;
for(; $c < 32; $c++)
{
$r = rand(0, 61);
$key .= $charset[$r];
}
$_SESSION['key'] = $key;
echo $key;
}
else
echo ("_SESSION_REGISTERED_");
?>


[size=medium]AUTH.PHP[/size]

    <?php
session_start();
$key = $_SESSION['key'];
$user = $_POST['user'];
$hash = $_POST['hash'];
$pass = $_POST['pass'];

//get password from db but this as an example for now
$username = 'codeprada'; // =D
$password = 'password'; // totally uncrackable
//
$_SESSION['user'] = $username;
$password = hash('sha512', $password, false);
$server_gen_hash = hash('sha512', $key . $password, false);
if(strcmp($hash, $server_gen_hash) == 0 && strcmp($user, $username) == 0)
{
$key2 = hash('sha512', $server_gen_hash . $key, false);

setcookie("authenticate", $server_gen_hash, 0, "/", "", false);
setcookie("validate", $key2, 0, "/", "", false);

session_register($server_gen_hash);
session_register($key2);
session_register(hash('sha512', $username, false));

echo("You have logged in successfully!");
}
else
echo("Please check your username or password and try again");
?>



[size=medium]SAMPLE_PAGE.PHP[/size]

    <?php
session_start();
$validate = hash('sha512', $_COOKIE["authenticate"] . $_SESSION['key'], false);
$username = hash('sha512', $_SESSION['user'], false);
if (!session_is_registered($_COOKIE["authenticate"]) || !session_is_registered($validate) || !session_is_registered($username)) {
header("Location:index.php");
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="https://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Sample Page</title>
</head>

<body>
<p style="font-size:48px">Congratulations if you're seeing this page!!</p>
<a href="index.php">Back to Login Page</a>
</body>
</html>



[size=medium]LOGOUT.PHP[/size]

    <?php
session_start();
session_destroy();
setcookie("authenticate", "", time() - 3600);
setcookie("validate", "", time() - 3600);
header("Location:index.php");
?>



[size=medium]INDEX.PHP[/size]

    <?php session_start() ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="https://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>LOGIN</title>
<script type="text/javascript" src="sha512.js"></script>
<script type="text/javascript">
document.oncontextmenu = function() { return false; } //disable right clicking
function getKey()
{
var xmlhttp;
if (window.XMLHttpRequest)
xmlhttp = new XMLHttpRequest();
else
xmlhttp = new ActiveXObject("Microsoft.XMLHTTPREQUEST");
xmlhttp.onreadystatechange = function() {
if(xmlhttp.status == 200 && xmlhttp.readyState == 4) {
var str = xmlhttp.responseText;
var expr = /^_SESSION_REGISTERED_/;
if (str.search(expr) == -1 ) {
if (str.length > 32)
//this is only because 000webhost concats a counter to the key and i only need the first 32 characters since my key is 32 chars long Smile
str = str.substr(0, 32);
document.getElementById("key").value = str;
document.getElementById("login").disabled = false;
}
else{
document.getElementById("results").innerHTML = "You are already logged in! " + "Logout <a href=\"logout.php\">Here</a>";
return;
}
}
}
xmlhttp.open("GET", "challenge.php", true);
xmlhttp.send();
}

function login()
{
var xmlhttp;
if (window.XMLHttpRequest)
xmlhttp = new XMLHttpRequest();
else
xmlhttp = new ActiveXObject("Microsoft.XMLHTTPREQUEST");

var key = document.getElementById("key").value;
var pass = hex_sha512(document.getElementById("password").value);
var auth = hex_sha512(key + pass);

xmlhttp.onreadystatechange = function() {
if(xmlhttp.status == 200 && xmlhttp.readyState == 4)
document.getElementById("results").innerHTML = xmlhttp.responseText;
}

document.getElementById("results").innerHTML = "Please wait...";
var str = "user=" + document.getElementById("username").value + "&hash=" + auth + "&pass=" + pass;
xmlhttp.open("POST", "auth.php", true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send(str);
}

</script>
</head>

<body onload="getKey()" style="background-color:#CC">
<div align="center" style="border:thin solid black; width:400px">
<form id="form1" name="form1">
<table>
<tr>
<td>Username</td>
<td><input type="text" id="username" name="username" size="30" /></td>
</tr>
<tr>
<td>Password</td>
<td><input type="password" id="password" name="password" size="30" /></td>
</tr>
</table>
<input type="hidden" id="key" name="key" />
</form>
<button id="login" disabled="disabled" onclick="login()">LOGIN</button>
</div>
<div id="results"></div>
If you can see this page =><a href="sample_page.php"> Sample Page </a> then you've successfully registered.
</body>
</html>




source You must login or register to view this content.

Copyright © 2024, NextGenUpdate.
All Rights Reserved.

Gray NextGenUpdate Logo