Am developing a secure login system for a web interface to a sensitive area of our company.
I wanted to do something a little bit different than using the normal login method
client sends password as clear text --> server hashes password and compare against stored hash
so I came up with a way to salt the password, hash it and then send the hash so the password is hashed before being sent so even if it is intercepted during transmission only the hash is captured which is useless as the random string which is hashed with the password changes each session.
This has 2 advantages
1. As mentioned above it stops the capturing of the password during transmission
2. If logging in from an internet cafe or similar there is no chance of the browser storing the password as it will store the hash.
The way it works is as so :
1. User enters password
2. Password is hashed
3. Random key is added to password hash
4. Combined key and hashed password is rehashed and sent to server
the random key that is used to salt the password is passed in the session
when the hash is received by the server it takes the normal password hash adds the key from the session to it hashes the combination and compares it to the one received from the form.
The reason I hash the password twice (once on its own and once when it has been salted) is due to the fact that the password will be stored in the DB as a hash.
Anyways on with the code :
(btw in these examples the username/password is hard coded but in final example this will be checked against the database)
Page with form
login scriptCode:<?php
$default_username = "admin";
$default_password = md5(test);
session_start();
if($_SESSION['key'] == "")
{
$random_string = ((date("dmyHi") + rand(0, 3000)) * 5);
$_SESSION['key'] = $random_string;
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Secure Login System</title>
<style type="text/css">
<!--
body,td,th {
font-family: Arial, Helvetica, sans-serif;
font-size: 10px;
color: #999999;
}
body {
background-color: #333333;
}
.container {
background: #333333;
padding: 10px;
width: 250px;
border: thin solid #999999;
margin: auto;
}
input {
font: 10px Arial, Helvetica, sans-serif;
color: #999999;
border: thin solid #999999;
background-color: #333333;
}
a:link {
color: #999999;
}
a:visited {
color: #999999;
}
a:hover {
color: #999999;
}
a:active {
color: #999999;
}
-->
</style>
<script language="JavaScript" src="md5.js"></script>
</head>
<body>
<div class="container">
<?php
//read cookie
$cvalue = $_COOKIE["secure_login"];
//get username and password from cookie
list($c_name, $c_pass) = split(":", $cvalue);
$full_pass = md5($_SESSION['key'].$default_password);
if($full_pass == $c_pass && $c_name == $default_username)
{
echo "You are logged in<br />";
echo "<a href=\"logout.php\">Logout?</a>";
}
else
{?>
<form id="form1" name="form1" method="post" action="login.php">
<table width="100%" border="0" cellspacing="3">
<tr>
<td width="31%">Username : </td>
<td width="69%"><input name="username" type="text" id="username" /></td>
</tr>
<tr>
<td>Password : </td>
<td><input name="password" type="text" id="password" /></td>
</tr>
<tr>
<td></td>
<td><input type="submit" name="Submit" value="Login" <?php echo 'onclick="password.value = calcMD5(\''.$random_string.'\' + calcMD5(password.value))"'; ?> /></td>
</tr>
</table>
</form>
<?php } ?>
</div>
</body>
</html>
logout page (with thanks to php.net)Code:<?php
session_start();
$username = $_POST['username'];
$password = $_POST['password'];
$default_username = "admin";
$default_password = md5(test);
$full_pass = md5($_SESSION['key'].$default_password);
if($full_pass == $password && $username == $default_username)
{
setcookie( "secure_login", "$username:$password" );
get_url("index.php");
}
else
{
die("Error With Login");
}
function get_url($url)
{
header("Location: $url");
echo "<html>\n<head>\n";
echo "<meta http-equiv=\"refresh\" content=\"2;url=$url/\">\n";
echo "</meta></head>\n<body>\n";
echo "You will be redirected to the site - if you are not click <a href=\"$url\">here</a>\n";
echo "<script LANGUAGE=\"JavaScript\">\n";
echo "window.location=\"$url\";";
echo "</script>";
echo "\n";
echo "</body>\n</html>";
}
?>
I also used the Javascript md5 script by Greg Holt [ http://pajhome.org.uk ]Code:<?php
// Initialize the session.
// If you are using session_name("something"), don't forget it now!
session_start();
// Unset all of the session variables.
$_SESSION = array();
// If it's desired to kill the session, also delete the session cookie.
// Note: This will destroy the session, and not just the session data!
if (isset($_COOKIE[session_name()])) {
setcookie(session_name(), '', time()-42000, '/');
}
// Finally, destroy the session.
session_destroy();
setcookie ("secure_login", "", time()-99999);
get_url("index.php");
function get_url($url)
{
header("Location: $url");
echo "<html>\n<head>\n";
echo "<meta http-equiv=\"refresh\" content=\"2;url=$url/\">\n";
echo "</meta></head>\n<body>\n";
echo "You will be redirected to the site - if you are not click <a href=\"$url\">here</a>\n";
echo "<script LANGUAGE=\"JavaScript\">\n";
echo "window.location=\"$url\";";
echo "</script>";
echo "\n";
echo "</body>\n</html>";
}
?>
comments?Code:/*
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
* Digest Algorithm, as defined in RFC 1321.
* Copyright (C) Paul Johnston 1999 - 2000.
* Updated by Greg Holt 2000 - 2001.
* See http://pajhome.org.uk/site/legal.html for details.
*/
/*
* Convert a 32-bit number to a hex string with ls-byte first
*/
var hex_chr = "0123456789abcdef";
function rhex(num)
{
str = "";
for(j = 0; j <= 3; j++)
str += hex_chr.charAt((num >> (j * 8 + 4)) & 0x0F) +
hex_chr.charAt((num >> (j * 8)) & 0x0F);
return str;
}
/*
* Convert a string to a sequence of 16-word blocks, stored as an array.
* Append padding bits and the length, as described in the MD5 standard.
*/
function str2blks_MD5(str)
{
nblk = ((str.length + 8) >> 6) + 1;
blks = new Array(nblk * 16);
for(i = 0; i < nblk * 16; i++) blks[i] = 0;
for(i = 0; i < str.length; i++)
blks[i >> 2] |= str.charCodeAt(i) << ((i % 4) * 8);
blks[i >> 2] |= 0x80 << ((i % 4) * 8);
blks[nblk * 16 - 2] = str.length * 8;
return blks;
}
/*
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
* to work around bugs in some JS interpreters.
*/
function add(x, y)
{
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
/*
* Bitwise rotate a 32-bit number to the left
*/
function rol(num, cnt)
{
return (num << cnt) | (num >>> (32 - cnt));
}
/*
* These functions implement the basic operation for each round of the
* algorithm.
*/
function cmn(q, a, b, x, s, t)
{
return add(rol(add(add(a, q), add(x, t)), s), b);
}
function ff(a, b, c, d, x, s, t)
{
return cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function gg(a, b, c, d, x, s, t)
{
return cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function hh(a, b, c, d, x, s, t)
{
return cmn(b ^ c ^ d, a, b, x, s, t);
}
function ii(a, b, c, d, x, s, t)
{
return cmn(c ^ (b | (~d)), a, b, x, s, t);
}
/*
* Take a string and return the hex representation of its MD5.
*/
function calcMD5(str)
{
x = str2blks_MD5(str);
a = 1732584193;
b = -271733879;
c = -1732584194;
d = 271733878;
for(i = 0; i < x.length; i += 16)
{
olda = a;
oldb = b;
oldc = c;
oldd = d;
a = ff(a, b, c, d, x[i+ 0], 7 , -680876936);
d = ff(d, a, b, c, x[i+ 1], 12, -389564586);
c = ff(c, d, a, b, x[i+ 2], 17, 606105819);
b = ff(b, c, d, a, x[i+ 3], 22, -1044525330);
a = ff(a, b, c, d, x[i+ 4], 7 , -176418897);
d = ff(d, a, b, c, x[i+ 5], 12, 1200080426);
c = ff(c, d, a, b, x[i+ 6], 17, -1473231341);
b = ff(b, c, d, a, x[i+ 7], 22, -45705983);
a = ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
d = ff(d, a, b, c, x[i+ 9], 12, -1958414417);
c = ff(c, d, a, b, x[i+10], 17, -42063);
b = ff(b, c, d, a, x[i+11], 22, -1990404162);
a = ff(a, b, c, d, x[i+12], 7 , 1804603682);
d = ff(d, a, b, c, x[i+13], 12, -40341101);
c = ff(c, d, a, b, x[i+14], 17, -1502002290);
b = ff(b, c, d, a, x[i+15], 22, 1236535329);
a = gg(a, b, c, d, x[i+ 1], 5 , -165796510);
d = gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
c = gg(c, d, a, b, x[i+11], 14, 643717713);
b = gg(b, c, d, a, x[i+ 0], 20, -373897302);
a = gg(a, b, c, d, x[i+ 5], 5 , -701558691);
d = gg(d, a, b, c, x[i+10], 9 , 38016083);
c = gg(c, d, a, b, x[i+15], 14, -660478335);
b = gg(b, c, d, a, x[i+ 4], 20, -405537848);
a = gg(a, b, c, d, x[i+ 9], 5 , 568446438);
d = gg(d, a, b, c, x[i+14], 9 , -1019803690);
c = gg(c, d, a, b, x[i+ 3], 14, -187363961);
b = gg(b, c, d, a, x[i+ 8], 20, 1163531501);
a = gg(a, b, c, d, x[i+13], 5 , -1444681467);
d = gg(d, a, b, c, x[i+ 2], 9 , -51403784);
c = gg(c, d, a, b, x[i+ 7], 14, 1735328473);
b = gg(b, c, d, a, x[i+12], 20, -1926607734);
a = hh(a, b, c, d, x[i+ 5], 4 , -378558);
d = hh(d, a, b, c, x[i+ 8], 11, -2022574463);
c = hh(c, d, a, b, x[i+11], 16, 1839030562);
b = hh(b, c, d, a, x[i+14], 23, -35309556);
a = hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
d = hh(d, a, b, c, x[i+ 4], 11, 1272893353);
c = hh(c, d, a, b, x[i+ 7], 16, -155497632);
b = hh(b, c, d, a, x[i+10], 23, -1094730640);
a = hh(a, b, c, d, x[i+13], 4 , 681279174);
d = hh(d, a, b, c, x[i+ 0], 11, -358537222);
c = hh(c, d, a, b, x[i+ 3], 16, -722521979);
b = hh(b, c, d, a, x[i+ 6], 23, 76029189);
a = hh(a, b, c, d, x[i+ 9], 4 , -640364487);
d = hh(d, a, b, c, x[i+12], 11, -421815835);
c = hh(c, d, a, b, x[i+15], 16, 530742520);
b = hh(b, c, d, a, x[i+ 2], 23, -995338651);
a = ii(a, b, c, d, x[i+ 0], 6 , -198630844);
d = ii(d, a, b, c, x[i+ 7], 10, 1126891415);
c = ii(c, d, a, b, x[i+14], 15, -1416354905);
b = ii(b, c, d, a, x[i+ 5], 21, -57434055);
a = ii(a, b, c, d, x[i+12], 6 , 1700485571);
d = ii(d, a, b, c, x[i+ 3], 10, -1894986606);
c = ii(c, d, a, b, x[i+10], 15, -1051523);
b = ii(b, c, d, a, x[i+ 1], 21, -2054922799);
a = ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
d = ii(d, a, b, c, x[i+15], 10, -30611744);
c = ii(c, d, a, b, x[i+ 6], 15, -1560198380);
b = ii(b, c, d, a, x[i+13], 21, 1309151649);
a = ii(a, b, c, d, x[i+ 4], 6 , -145523070);
d = ii(d, a, b, c, x[i+11], 10, -1120210379);
c = ii(c, d, a, b, x[i+ 2], 15, 718787259);
b = ii(b, c, d, a, x[i+ 9], 21, -343485551);
a = add(a, olda);
b = add(b, oldb);
c = add(c, oldc);
d = add(d, oldd);
}
return rhex(a) + rhex(b) + rhex(c) + rhex(d);
}
//next steps is to add in number of login attempts etc - but this is just the basic login system with the salt
