Virtual Keyboard Login – Version wicked.evil [avoid screenshots]
Mon, 28th Jul, '08
Ok, so we had virtual keyboards for some time on login pages being served worldwide. In fact so long that we had this. So we have virtual keyboards here again, and some smartness, some.
Earlier in this blog we covered some crypt way to send passwords to the server from the browser, and thanks to the response, i feel motivated enough. Now we are onto making a virtual keyboard, and yeah, this is a proof-of-concept and you are free to take it to the moon alongwith you.
We are just going to blank out all buttons just before the user is going to click on one. Basically do a backgroundColor = fontColor on all buttons to make it difficult what is written on the buttons on mouseover and restore on mouseout. Normally a user figures out which button to click on and then positions the mouse on the button and clicks, so if the button is showing what is written on it, definitely some proof-of-concept program can take a snapshot of the web page to figure out which button was clicked on. We are just going to wipe the face of the button off. For some more fun, we are going to randomize the order of buttons at will by calling randomizekeys() and supplying the order of the keys as an argument. And yeah, the styling class is closely tied to the javascript functions, so keep that in mind while playing with styles or the javascript. So here we go[look at the onload handler in the body tag] …
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
<title>Virtual Login Panel</title>
<style>
.loginnumkey {
background:#000;
color:#FFF;
padding:5px 0 5px 0;
min-width:40px;
font-size:16px;
font-family:tahoma;
margin:1px;
}
</style>
<script>
function randomizekeys(assigncode, numkeysclass)
{
var j = 0;
var els = document.getElementsByTagName('input');
var elsLen = els.length;
var pattern = new RegExp('\\b'+numkeysclass+'\\b');
for (var i = 0; i < elsLen; i++)
{
if ( pattern.test(els[i].className) && j < assigncode.length)
{
els[i].value = assigncode[j];
j++;
}
}
}
function keysoff(numkeysclass)
{
var i = 0;
var els = document.getElementsByTagName('input');
var elsLen = els.length;
var pattern = new RegExp('\\b'+numkeysclass+'\\b');
for (i = 0; i < elsLen; i++)
{
if ( pattern.test(els[i].className) )
{
els[i].style.backgroundColor = '#FFF';
}
}
}
function keyson(numkeysclass)
{
var i = 0;
var els = document.getElementsByTagName('input');
var elsLen = els.length;
var pattern = new RegExp('\\b'+numkeysclass+'\\b');
for (i = 0; i < elsLen; i++)
{
if ( pattern.test(els[i].className) )
{
els[i].style.backgroundColor = '#000';
}
}
}
function clicknumkey(inputid, inputvalue)
{
document.getElementById(inputid).value =
document.getElementById(inputid).value + inputvalue;
}
</script>
</head>
<body onload="javascript:randomizekeys('1095673824', 'loginnumkey');">
<input type='text' id='passwordbox'>
<br><br>
<input type='button' id='lkey1' value='1' class='loginnumkey'
onclick="javascript:clicknumkey('passwordbox', this.value);"
onmouseover="javascript:keysoff('loginnumkey');"
onmouseout="javascript:keyson('loginnumkey');">
<input type='button' id='lkey2' value='2' class='loginnumkey'
onclick="javascript:clicknumkey('passwordbox', this.value);"
onmouseover="javascript:keysoff('loginnumkey');"
onmouseout="javascript:keyson('loginnumkey');">
<input type='button' id='lkey3' value='3' class='loginnumkey'
onclick="javascript:clicknumkey('passwordbox', this.value);"
onmouseover="javascript:keysoff('loginnumkey');"
onmouseout="javascript:keyson('loginnumkey');">
<br>
<input type='button' id='lkey4' value='4' class='loginnumkey'
onclick="javascript:clicknumkey('passwordbox', this.value);"
onmouseover="javascript:keysoff('loginnumkey');"
onmouseout="javascript:keyson('loginnumkey');">
<input type='button' id='lkey5' value='5' class='loginnumkey'
onclick="javascript:clicknumkey('passwordbox', this.value);"
onmouseover="javascript:keysoff('loginnumkey');"
onmouseout="javascript:keyson('loginnumkey');">
<input type='button' id='lkey6' value='6' class='loginnumkey'
onclick="javascript:clicknumkey('passwordbox', this.value);"
onmouseover="javascript:keysoff('loginnumkey');"
onmouseout="javascript:keyson('loginnumkey');">
<br>
<input type='button' id='lkey7' value='7' class='loginnumkey'
onclick="javascript:clicknumkey('passwordbox', this.value);"
onmouseover="javascript:keysoff('loginnumkey');"
onmouseout="javascript:keyson('loginnumkey');">
<input type='button' id='lkey8' value='8' class='loginnumkey'
onclick="javascript:clicknumkey('passwordbox', this.value);"
onmouseover="javascript:keysoff('loginnumkey');"
onmouseout="javascript:keyson('loginnumkey');">
<input type='button' id='lkey9' value='9' class='loginnumkey'
onclick="javascript:clicknumkey('passwordbox', this.value);"
onmouseover="javascript:keysoff('loginnumkey');"
onmouseout="javascript:keyson('loginnumkey');">
<br>
<input type='button' id='lkey0' value='0' class='loginnumkey'
onclick="javascript:clicknumkey('passwordbox', this.value);"
onmouseover="javascript:keysoff('loginnumkey');"
onmouseout="javascript:keyson('loginnumkey');">
<input type='button' id='lkeyclear' value='reset' class='loginnumkey'
onclick="javascript:document.getElementById('passwordbox').value='';"
onmouseover="javascript:keysoff('loginnumkey');"
onmouseout="javascript:keyson('loginnumkey');">
</body>
</html>
This may not work in IE, I mean this code snippet. If you want to make it work, just fiddle with i, j declarations in the function randomizekeys(), like moving them around in the function.
Preparing a secure login form with PHP & JavaScript
Wed, 26th Dec, '07
We have had encryption, we have had SSLs, … well we also had digitally signed certificates, but where’s the hack?? How can you cook up a secure login form that does the following:
[1] doesn’t send the login information in clear-text
[2] in case somebody is sniffing the line, he/she shouldn’t be able to login with the sniffed information
So, with the above information in hand, here is what we do, and how we do.
You need:
[1] http://www.webtoolkit.info/javascript-md5.html [javascript implementation of MD5]
[2] Two php functions. runquery($query) , which will run a query supplied as string & getcol($query) will get the column asked for in a select statement.
Now, create a table, if you don’t already have, to store user information. What we do want to be stored is the login timestamp.
create table user(
loginid varchar(200),
password varchar(200),
lastLoginTS bigint
);
Now your login.php file should look like this:
<html>
<head>
<title>Secure Login Form</title>
<script type=”text/javascript” src=”md5.js”></script>
</head>
<body>
<form action=”dologin.php” method=”post” onsubmit=”javascript:document.getElementById(‘phash’).value = MD5(document.getElementById(‘password’).value + document.getElementById(‘hts’).value); document.getElementById(‘password’).value = ” ;”>
LoginID: <input type=”text” name=”loginid”><br>
Password: <input type=”password” name=”password” id=”password”><br>
<?php
$TS = time(); //the current timestamp
echo “<input type=’hidden’ value=’”.$TS.”‘ name=’hts’ id=’hts’><br>”;
?>
<input type=’hidden’ name=’phash’ id=’phash’ value=”>
<input type=”submit” value=”send”>
</form>
</body>
</html>
This file assumes in the line “<script type=”text/javascript” src=”md5.js”></script>” that you have a file named md5.js in the same directory as login.php, and the javascript file should have a function named MD5(). So make sure this is the case. Next up is dologin.php:
<?php
$loginid = $_REQUEST['loginid'];
$phash = $_REQUEST['phash'];
$hts = $_REQUEST['hts'];
$password = getcolumn(“select password from user where loginid=’$loginid’;”);
$lastLoginTS = getcolumn(“select lastLoginTS from user where loginid=’$loginid’;”);
if(strlen($loginid) > 0 && strlen($phash) > 0 && $phash == md5($password.$hts) && $hts > $lastLoginTS)
{
runquery(“update user set lastLoginTS=’”.time().”‘ where loginid=’$loginid’;”);
echo “done”;
}
else
echo “failed”;
?>
That’s it. So now what is the deal here. This is your regular login form except that the password is hashed with a timestamp value sent in a hidden form field named ‘hts’. The hashing is done in the event handler for the Javascript onsubmit event, and the password field is cleared as well, to prevent it from being sent in the clear.
The server receives the loginid, timestamp and the hashed value from the client. Retrieve from your database the original password for the loginid specified and calculate another hash at the server with the help of the retrieved original password and the timestamp sent by the client. If the user typed the password correctly, the hashes will match.
This method of course, sort of, encrypts the password and hence prevents the password from being sent in clear, should anybody be sniffing the lines. But should anybody be really sniffing the lines, he/she can just store the values and send them again and again to validate him/herself at the server posing as the valid user. To prevent that, there is another check at the server just before validating. The timestamp sent by the client should be always greater than the last login timestamp stored in the database for that user. Since the last login timestamp is only updated on a successful login, as soon as a valid user logs in, the last login timestamp for the user is updated in the database, and as a result, the sniffed information is rendered stale. The hash now needs to be calculated again using a fresh timestamp and a password which only the user and server know.
I hope this suffices for most of you out there.
UPDATE : This is a proof of concept. The system described here lacks certain things which are very obvious and shouldn’t omit them just because I haven’t mentioned them here to make it simple to grasp. Foremost[thanks William], don’t store passwords in cleartext on the server. Try looking up “hashing password with salts” for that.




