PHP DevCenter
oreilly.comSafari Books Online.Conferences.

advertisement


Securing Web Forms with PEAR's Text_CAPTCHA

by Marcus Whitney
03/31/2005

When you have publicly available forms on the Web, you are always prone to attack by people who want to use your application for their own purposes. Forums, polls, guestbooks, and blogs are the popular places for robots to try to generate inauthentic posts on your site. Many sites, such as Yahoo, now employ CAPTCHA. CAPTCHA, or "completely automated public Turing test to tell computers and humans apart," is a project of the Carnegie Mellon School of Computer Science that sets out to determine if a human or a computer initiated a request. CAPTCHA technology enables you to discern human requests from computer generated requests on the Web, where such a distinction is difficult.

Note: According to Wikipedia, a Turing test is a proposal for a test of a machine's capability to perform human-like conversation.

You have probably seen the CAPTCHA project in action at some of your Web destinations. Its principal tool is a randomly created image that contains a phrase unmentioned in computer-readable text on the rendered page. The form asks the user to provide the phrase. If the form post does not contain the correct phrase, you can safely assume either the human made a user error, or it wasn't a human at all.

Installing Text_CAPTCHA

Thanks to Christian Wenz, PEAR has a package entirely dedicated to providing these tests as security tools in your web application. The Text_CAPTCHA package uses PHP's GD functionality to create dynamic images with random phrases in a simple object-oriented interface. Before you can use Text_CAPTCHA, you must have GD installed with support for JPEGs, PNGs and TrueType fonts. For more information, see PHP Image Functions.

Text_CAPTCHA depends on two other PEAR packages, Image_Text and Text_Password. It uses Text_Password to generate the random phrase used in the CAPTCHA test and Image_Text to generate an image file with text in it. The process for installing Text_CAPTCHA at the command line is:

$ pear install Text_Password
$ pear install Image_Text
$ pear install --alldeps Text_CAPTCHA

Presenting CAPTCHAs

Now it's time to put this package to work. A simple and often-used interface to implement this new security measure is the comments form on a blog. In this form you typically capture the name, email, and comment from the person posting to your blog. A form might look as follows:

<form method="POST" action="">
   Name: <input type="text" name="name" /><br />
   Email: <input type="text" name="email" /><br />
   Comment: <textarea name="comment"></textarea>
   <input type="submit" />
</form>

To add a CAPTCHA technology to the form, add an image tag above the submit button for human verification:

    Please enter the text in the image below: <input type="text"
name="captcha_phrase" /><br />

    <img src="captcha.jpg" />

Here's where Text_CAPTCHA comes in. Prior to outputting the form, implement Text_CAPTCHA with code like the following:

<?php
require_once('Text/CAPTCHA.php');
$captcha = Text_CAPTCHA::factory('Image');
$captcha->init(150,150);
?>

Related Reading

Upgrading to PHP 5
By Adam Trachtenberg

The first line requires the Text_CAPTCHA.php file. The second line uses Text_CAPTCHA's factory method to return an object from a subclass of Text_CAPTCHA. Text_CAPTCHA's design allows for different driver types to render CAPTCHA. Remember, CAPTCHA is a technology for telling humans apart from computers, not just for generating images to do so. The argument to the factory method is Image, instructing Text_CAPTCHA to create an object with the Image driver in order to create a random image. The third line initializes the Text_CAPTCHA object and prepares it for use.

The initialization phase bears more examination. To start, it accepts two parameters: the width and height of the randomly created image. These parameters are optional, with default values of 200 and 80, respectively. init() also accepts two additional, optional parameters. The first is $phrase, which allows the programmer to set the secret phrase to use in the generated image. If you don't pass in a phrase, init() will automatically create a phrase for you with a maximum of eight characters. The final parameter is an $options array, which allows you to pass options into PEAR's Image_Text object, which init() uses to create the image with text.

The $options array is an important parameter for this use of Text_CAPTCHA, as these options configure the font and font size to use, as well as the path to the fonts on your system. (The default font path will probably not work, unless you run this tutorial on Windows.) To set these, create and pass an array into the init() method as follows:

$text_image_options = array(
    'font_size'=>'20',
	'font_path'=>'/path/to/fonts/',
    'font_file'=>'ARIAL.TTF'
);

$captcha->init(150,150,NULL,$text_image_options);

Once init() has created the image and the phrase, the rest of the process is pretty simple. You must create an image file that the browser can display. init() doesn't do that for you. In order to access the image, use the getCAPTCHAAsJPEG() or getCAPTCHAAsPNG() accessor methods, both of which return the randomly generated image data in a buffer so that you can easily dump the data into a fresh file. If you are using PHP4, the way to do this is:

  $image_data = $captcha->getCAPTCHAAsJPEG();
  $handle = fopen('captcha.jpg', 'a');
  fwrite($handle, $image_data);
  fclose($handle);

PHP5 has made this a lot easier through the new file_put_contents function:

  $image_data = $captcha->getCAPTCHAAsPNG();
  file_put_contents('captcha.png',$image_data);

The next thing to do is to extract the phrase from the current object and store it in a session variable. If you haven't created a session for this user, now is a good time to do so:

session_start();

Now, using the getPhrase() accessor method of Text_CAPTCHA, set a session variable to the phrase in preparation for the test on the form post:

$_SESSION['captcha_phrase'] = $captcha->getPhrase();

Validating CAPTCHAs

That's it for the form side. It's time now for the code that determines if the user is a human or not. On the form post, simply check to see if the posted phrase is set and equals the value in the session. If they match, you can proceed with the appropriate POST action. Otherwise, discard the form post and take further steps as you see fit. The following code demonstrates the logic in asserting the CAPTCHA test:

<?php
  session_start();
  if (isset($_POST['captcha_phrase']) &&
      $_POST['captcha_phrase'] == $_SESSION['captcha_phrase'])
  {
    // do post activity
  }
  else {
    // do security audit
  }
?>

Conclusion

CAPTCHA can be a great way to limit the amount of successful, unwanted HTTP POST requests in your application. Text_CAPTCHA provides an adequate object to quickly implement this functionality. At the present time, the package is in alpha, and therefore not officially production-ready. However, it is off to a great start and brings a touch of security consciousness to PEAR that is always appreciated. Happy CAPTCHA-ing!

Marcus Whitney is Director of Product Development for Emma, an email marketing service powering the email marketing efforts of over 1800 organizations around the world with offices in New York City (where he's from) and Nashville (where he lives).


Return to the PHP DevCenter.


Valuable Online Certification Training

Online Certification for Your Career
Earn a Certificate for Professional Development from the University of Illinois Office of Continuing Education upon completion of each online certificate program.

PHP/SQL Programming Certificate — The PHP/SQL Programming Certificate series is comprised of four courses covering beginning to advanced PHP programming, beginning to advanced database programming using the SQL language, database theory, and integrated Web 2.0 programming using PHP and SQL on the Unix/Linux mySQL platform.

Enroll today!


Sponsored by: