Skip to page content or skip to Accesskey List.
Search evolt.org
evolt.org login: or register

Work

Main Page Content

Securing Forms - Random Image

Rated 0 (Add your rating)

Log in to add a comment
(8 comments so far)

Want more?

 
Picture of DaButcher

Olav Alexander Mjelde

Member info | Full bio

User since: December 20, 2004

Last login: May 26, 2006

Articles written: 1

There are several different applications for securing your forms:

When you...

  • Don't want someone doubleposting
  • Want to protect your pages from computerized registrations (spam)
  • want to protect some pages from google or others, without .htaccess

Considerations

There are some considerations, which actually might block people from your forms!

  • People who are visually impaired will not see the image!
  • People who use non-GUI browsers will not see the image!

Simple steps to help those with no GUI

Provide an alternative way of input, so that the visual-impaired can contact you. This might include options like:

  • Emailing you for manual input
  • Some sort of over-ride function, if they type some secret code in the querystring

There are several ways to do this, and I urge you to think about, and consider that not everyone on the www has the same advantages as you and me. Those advantages include that you and me can see images in our web-browsers.

Backend

If you are the one who wants things to be quick and simple, this is a great code-sample for your further reading. While some people might also use mySQL for a system like this, you might agree that it's not needed, after seeing the result.

Functions Used

To make a script like this, there are several functions that one needs to use. Since this script is quite simple constructed, it does not use a great deal of functions.
  • session_start() - Starts the session
  • unset() - Unsets a variable
  • header() - Send a raw HTTP header
  • imagecreatefrompng() - Create a new image from file or URL
  • imagecolorallocate() - Allocate a color for an image
  • imagesx() - Returns the width of the image
  • imagesy() - Returns the height of the image
  • imagestring() - Draw a string horizontally
  • imagepng() - Output a PNG image to either the browser or a file
  • imagedestroy() - Frees any memory associated with image
  • substr() - Return part of a string
  • md5() - Calculate the md5 hash of a string
  • time() - Return current Unix timestamp

Generating the password, using some of the functions above

As quoted from the manual on www.php.net
Returns the current time measured in the number of seconds since the Unix Epoch (January 1 1970 00:00:00 GMT).

What does this mean for us?

We want to generate a random password!

Why not use the time()?

The time() will be unique, since we all know: time passes!

However, one might think that the time() might output in a format which might be un-neccessarily hard for the user to read (due to many digits). You and me both know that when we are paying bills, we have to read the account-numbers often twice or three times, to make sure that we have written them correctly. This is however easier if the key can contain both a-z and 0-9. We all know that time is just presented in 0-9, so how do we do this?

This is why we only want a part of the time() that we will use for a key. To also make the key more readable, we wrap the time() inside md5(). The md5 will then make the key with both integers and letters. (a-z, 0-9).

For this tutorial, the key-length is set to 6 characters, which should be more than enough for securing your forms. If you want to calculate how secure your key is, the formula is:

Your key will have a pattern like: xxxxxx (6 characters).
They might be (a-z, 0-9), which gives 25 possibilities in a-z + 10 possibilities in 0-9.
That is a total of 35 possible characters in each character of the key.

35 ^ 6 = 1 838 265625 combinations for that key-length.

Also remember:
If the user inputs a wrong key, or reloads the page, the next key will be different, as it's based on the time() function. This makes the possibility for guessing a key:
1 / 1 838 265625 ~~ impossible.

Keeping the user on the inside

There are several ways of making a login script. One might use cookies, mysql, flatfiles or other ways. The most simple way of making a login-script, is to use the session variables.

While "regular" variables needs to be passed in the query-string, the session_variable does not. You simply start the session with session_start(), at the very top-most of your script. After that is done, you set the wanted variables with $_SESSION['variable_name'] = "value";

Backend Code

Check for authentication

This first file, checks if the user is authenticated. Then (if not authenticated), it will generate an random image. If that image is generated, the input by the user must EQUAL the key that the image is based on.

<?php
/* Session must always start at the very top of the php file! */
session_start();

if (isset(
$submit)) { // if user submitted the form
  
if ($submit == "logout") { // if user wants to logout
      
unset($_SESSION['key']); // unset the key
    
}
  }

// if the key is wrong, or not excistant
if ($_SESSION['key'] != $_POST['key'] || (!($_SESSION['key']))) {
  
$_SESSION['key'] = substr(md5(time()), 0, 6); // make a key
/* Make a form for inputing the key*/
  
echo "
  <form action=\"\" method=\"post\">
  <img src=\"img.php\" />
  <input type=\"text\" name=\"key\" />

  <input type=\"submit\" name=\"submit\" value=\"submit\" />
  </form>"
;
  }
else {
// if key is set and input is correct
// process the page
  
echo "
  <form action=\"\" method=\"post\">
  Access OK
  <input type=\"submit\" name=\"submit\" value=\"logout\" />
  </form>"
;
  }
?>

The image generator (img.php)

The image-generator simply applies a string (from the session variable 'key') on to an image, which in this script has to be /images/bg.png
<?php
// once again, start the session at the very top!
session_start();

/* if there is a key */
if ($_SESSION['key']) {
/* define that the browser should treat
  the output of this file as an image */
  
header("Content-type: image/png");

  
// set the string to the key
  
$string = $_SESSION['key'];

  
// create an temporary image from a PNG file
  
$im    = imagecreatefrompng("images/bg.png");

  
// get a color from the image (in this case, yellow)
  
$orange = imagecolorallocate($im, 220, 210, 60);

  
/* Now we need to get widh and height of the image, so that we can center the
  key on the image, so that it does not go outside of the borders or look strange */
  
$px    = (imagesx($im) - 7.5 * strlen($string)) / 2;
  
$h = (imagesy($im) - 7.5) / 2;

  
// here we write the key (the string)  on the image
  
imagestring($im, 3, $px, $h, $string, $orange);

  
// now create the final image
  
imagepng($im);

  
// to free up results, we need to destroy the temporary image.
  
imagedestroy($im);
  }
?>

Improvements that can be made

There are several improvements that can be made, like the ones mentioned above.The most important one of them all, is the one about the visual impaired, as they will not be able to view an image.

Suggested improvements

Submitted by gusnz on January 18, 2006 - 00:25.

Your system of using time() to generate a key is less than secure, unfortunately. Please modify it to generate truly random keys using a respected random number generator and random seed (try incorporating things like the current process ID of the server, the amount of free disk space, etc. etc.).

At the moment, a prospective attacker only has to parse the "Date:" HTTP header returned with the login page to obtain the server time, md5() the value, and POST it back.

Also, there are 26 letters in the alphabet :).

Perhaps also consider incorporating the term CAPTCHA into the article so users can find similar scripts/technology.

login or register to post comments

How about doing it this way!

Submitted by amirbilal on January 20, 2006 - 10:05.

<?php
function genText($length) {
$p_chars="AGHACEFHJKRSTVXY124579"; // can be any set of characters
while(strlen($out_str)< $length)
{
$out_str.=substr($p_chars,(rand()%(strlen($p_chars))),1);
}
return
$out_str;
}

$rand_string = genText(6);
// your image generation functionality goes afterwards...
?>

login or register to post comments

How about this way!!

Submitted by cDizzle on February 4, 2006 - 09:12.

like what amirbilal said, but what is better IMO is using { } (curly braces} instead of a substr; $p_chars{1} would be the first char, $p_chars{5} would be the fifth, and I dont think I need to say more than that about it. As with most (if not all) php code, you can use functions to return those numbers, or in other words, functions that return numbers where the number is supposed to go meaning the number is where its sposta be and i think thats obvious :p
<?php
function genText($length) {
$p_chars="AGHACEFHJKRSTVXY124579"; // can be any set of characters
while(strlen($out_str)< $length)
{
$out_str.= $p_chars{rand()%(strlen($p_chars))};
}
return
$out_str;
}

$rand_string = genText(6);
?>
http://www.phpwned.com - For all your PHP Learning needs :)

login or register to post comments

how about this

Submitted by fugazi on March 1, 2006 - 07:41.

Textbook example... Several other improvements come to mind. Peace out.

login or register to post comments

Talking about time...

Submitted by DaButcher on March 9, 2006 - 08:09.

Talking about time, the time/date on this article has been changed, somehow.. I made this tutorial in 2k5, lol.. Even so, yes, there are many things one can do to improve this. However, I will not do it, as I think a simple example like this, with tips from other members like you, will help others in learning/inspiration.. Thank you all for tips/tricks! I have many other scripts, some a great deal more advanced, but I lack the most important thing: Time. It unfortunately takes time to share resources, as one can not share them without commenting the code,etc.. Good luck for you future projects!

login or register to post comments

Audio Validation

Submitted by cianuro on November 19, 2006 - 12:59.

While the solution above is technically sound you maybe missed out on a much more efficient form of validation. Offering an audio sample of the text in the image. Many visually impaired people prefer to not have to go back to another application (Mail) and make the confirmation. A simple audio option would resolve this. Good article though. Regards. Dave Davis. Redflystudios Web Design

login or register to post comments

sometimes annoying

Submitted by AxelF on April 3, 2007 - 13:29.

Since I'm using a small self-made code snippet for security images in my bulletin board (registration part) the spam has gone down to 1 mail/week (from 10 mails/day). So the main idea is great. But - it can be very annoying if the image cant be read after ten thousend tries (like seen in many sites). So it should not be too secure. ;-) Axel

login or register to post comments

How smart are auto registration spam robots?

Submitted by Robberto on July 27, 2007 - 16:03.

Hi all,

I admin a couple boards, and had the spam nightmare even while I used the board script (phpbb) package visual confirmation system.

The way I solved my problem, and is still working like a charm, whith 0 spam registration since I implemented, is a manual edition in the reg form.

I basically added a hidden param, with a static value, and aborted the registration process in the other end if the value is not received via post.

Is a very simple and *almost* stupid solution, but it works! I used to have 30-50 spam registrations a week, and now have cero.

Which leads me to think robots work with the general implementations, if you customize, your script just a bit, robots will not bother you again.

login or register to post comments

The access keys for this page are: ALT (Control on a Mac) plus:

evolt.orgEvolt.org is an all-volunteer resource for web developers made up of a discussion list, a browser archive, and member-submitted articles. This article is the property of its author, please do not redistribute or use elsewhere without checking with the author.