Good morning,
I'm looking for a good way in which to present to the user a dynamic image containing a mixture of randomly chosen letters and numbers, which they must type out in order for a form submission to proceed successfully.
We've all seen them I expect - but I'm not happy with the way I've gone about doing this in the past.
Essentially I currently do this as below:
I generate a series of alpha numeric strings, using various sources (but essentially, simply hashing them to jumble them up a bit) as follows:
$humancode = md5(date("d-m-Y")).md5(uniqid(date("U"))).md5($_SERVER["REMOTE_ADDR"]);
I then present a dynamic image to the user, and ask them to enter the code into a box to confirm its a human, and not a screen scraping 'bot - and the image is displayed as follows:
<img height="25" width="100" src="/code.php?c=<?PHP print $humancode; ?>">
A "live" example looks like this:
src="code.php?c=d194870b84d36d24116f4eb84c9589d736b99041a5a8c0423fd9d4685856dd4808a8d76ee70de4de3ed0b116620cfc2d"
Of course, in order for this to work, the same "encrypted" string needs to be sent to the server as a result of form submission - therefore, in the form I have a hidden field with the same data:
<input type="hidden" name="humancode" value="d194870b84d36d24116f4eb84c9589d736b99041a5a8c0423fd9d4685856dd4808a8d76ee70de4de3ed0b116620cfc2d">
The image itself is dynamically created by "code.php", which executes the following:
header("Content-type: image/png");
$string = $_GET['c'];
$a = substr($string,32,1);
$b = substr($string,38,1);
$c = substr($string,10,1);
$d = substr($string,41,1);
$string = $a.$b.$c.$d;
$im = imagecreatefrompng("img/button2.png");
$orange = imagecolorallocate($im, 16, 182, 222);
$px = (imagesx($im) - 10.5 * strlen($string)) / 2;
$font = imageloadfont("img/andale12.gdf");
imagestring($im, $font, $px, 4, $string, $orange);
imagepng($im);
imagedestroy($im);
The problem is of course, that this entire system is locked into the fact that I have pre-determined the position of the characters I'm looking for - $a, $b, $c, $d are essentially constants and this is a security problem that would easily be broken down with a simply brute force approach.
On the back end, when the form is submitted, part of the validation process takes the hidden $humancode value, picks out the characters at position $a, $b, $c, $d and then compares that value against the user submitted code value.
Its as simple as:
if($enteredcode !== $requiredcode)
{
// Scream merry hell
}
else
{
// Proceed...
}
If they're the same, form submission continues, else it errors and screams merry hell at the user.
Now, whilst this system works, there are many things wrong with it:
- Its readily open to brute force attacks.
- It relies on 2 copies of variables $a,$b,$c,$d to be maintained, which is silly.
- Its clunky and crufty - i.e. it works, but its a bit poo in terms of approach.
So, does anyone have any ideas on how I should go about developing a much better version of this?
Incidentally, if you would like to see this in action, you can do so here:
http://www.etronika.co.uk/
Regards,
Brit.