SMBs

How do I... Generate strong passwords with PHP, PEAR, and PECL?

PHP's Text_Password and securepwd classes help you reduce the risk of user passwords being guessed by brute force attacks. There's also a PECL extension based on the cracklib library that you may use to test password strength. See how these tools work.

When you're in charge of a Web application's account registration and maintenance section, there are two things you can do to reduce the danger of user passwords being easily guessed via brute force attacks.

One option is to automatically generate secure passwords for users by using random characters that brute force techniques cannot easily break. The other, less aggressive, approach is to evaluate users' passwords and then provide them with feedback about whether the password is strong or weak.

PHP helps you accomplish both tasks by providing two pre-built classes that support these functions: securepwd and PEAR's Text_Password. There's also a PECL extension based on the cracklib library that you may use to test password strength. This tutorial explains how these tools work and how you can use them in your development environment to reduce the risks that accompany weak passwords.

Note: This tutorial assumes a working Apache/PHP development environment, with both the Text_Password and securepwd classes installed.

Creating pronounceable passwords

This simple example illustrates how Text_Password works:

<?php

// include class

include 'Text/Password.php';

// create password

$tp = new Text_Password();

echo $tp->create();

?>

The script reads in the class definition, initializes an instance of the Text_Password class, and calls its create() method to generate a random password. The create() method (which can also be called statically) generates a pronounceable password with a default length of 10 characters (e.g., 'sliocliost' or 'cougostouc'). This type of password stands up to a brute force attack because it's not a word in the dictionary. The fact that it's pronounceable makes it easier for users to remember it.

You can also pass create() an optional argument to control the length of the returned password. Consider the following variant, which generates a 22-character password:

<?php

// include class

include 'Text/Password.php';

// create password

$tp = new Text_Password();

echo $tp->create(22);

?>

Creating unpronounceable passwords

Another approach is to tell Text_Password to generate so-called unpronounceable passwords, which include numeric characters and symbols. Unpronounceable passwords are more difficult for users to remember and harder for hackers to guess, thus making them more secure.

You generate an unpronounceable password by calling Text_Password's create() method with an additional 'unpronounceable' parameter, like this:

<?php

// include class

include 'Text/Password.php';

// create password

$tp = new Text_Password();

echo $tp->create(10, 'unpronounceable');

?>

The output of this example might be something like 'yyAe&9lQqB' or 'ocm&AZ9oho'. It's not particularly easy on the eyes, but it's certainly difficult to guess.

Constraining passwords to a specific base

It's also possible to restrict generated passwords to a specific subset of characters (e.g., certain symbols and numbers) by passing the character list to the create() method as a third, optional argument. Here's an example that ensures the generated password only contains numbers between one and nine:

<?php

// include class

include 'Text/Password.php';

// create password

$tp = new Text_Password();

echo $tp->create(6, 'unpronounceable', '123456789');

?>
The output of this example might be something like '417934' or '396514'. Note: This only works when generating unpronounceable passwords.

You can also use the keywords 'numeric', 'alphabetical', or 'alphanumeric' (instead of a specific character sequence) to restrict passwords to the corresponding set of characters. Here's an example of generating unpronounceable passwords that only contain alphabetic characters:

<?php

// include class

include 'Text/Password.php';

// create password

$tp = new Text_Password();

echo $tp->create(6, 'unpronounceable', 'alphabetical');

?>

Creating multiple passwords at once

If you want to generate multiple passwords at once — either to offer users a wider choice or to register accounts in a batch — you can use the createMultiple() method instead of the create() method. The createMultiple() method accepts the same arguments as the create() method with one important difference: The first argument to createMultiple() must be the number of passwords to be created. The method's return value is an array containing the generated passwords.

Here's an example, which generates five unpronounceable passwords that are 12 characters long:

<?php

// include class

include 'Text/Password.php';

// create multiple passwords

$tp = new Text_Password();

$data = $tp->createMultiple(5, 12, 'unpronounceable');

echo implode("nn", $data);

?>

Here's an example of the output:

SM3wXTbf99_v

RiuG#GKBC7ob

IMiQEtLZbaFX

JzG5nyXM9ich

8BObhpHS1TNK

Creating obfuscated passwords

An interesting feature of the Text_Password class is its ability to generate passwords on the basis of the corresponding login names, using an obfuscation algorithm to make the password more difficult to guess. In addition to simply shuffling or reversing the login name, you can also use the XOR or ROT13 swap algorithms to generate passwords based on the login name. Here are examples:

<?php

// include class

include 'Text/Password.php';

// create password

$tp = new Text_Password();

echo "For login name 'parker': n";

echo "Shuffled: " . $tp->createFromLogin('parker', 'shuffle') . "n";

echo "Reversed: " . $tp->createFromLogin('parker', 'reverse') . "n";

echo "ROT13'd: " . $tp->createFromLogin('parker', 'rot13') . "n";

echo "ROT10'd: " . $tp->createFromLogin('parker', 'rotx', 10) . "n";

echo "XOR'd: " . $tp->createFromLogin('parker', 'xor', 1) . "n";

?>

Here's the output:

For login name 'parker':

Shuffled: erkapr

Reversed: rekrap

ROT13'd: cnexre

ROT10'd: zkbuob

XOR'd: q`sjds

It's important to note that, because these passwords are based on well-known, fairly insecure algorithms, they're not really that secure. Nevertheless, this feature may be useful when you're looking for a relatively simple two-way cipher.

Testing password weakness with securepwd

The securepwd class allows you to test how weak a password is and provide immediate feedback to users so that they can make the password more robust if necessary. This class exposes a check() method, which checks a password against a given login name and tests if it's similar (based on a dictionary word) or not long enough. Here's an example of securepwd in action:

<?php

// include class

include 'securepwd.inc.php';

// assume this is the password supplied by the user

$pwd = 'rekrap';

// create object

$securepwd = new securepwd(true, true, true, true, 'parker', 5, 'passwords.txt');

// check password

if (!$securepwd->check($pwd)) {

      echo "Weak password: ". $securepwd->geterror();

} else {

      echo "Strong password";

}

?>

In this case, because the password supplied is essentially the login name reversed, the check() method will immediately return the following error:

# Weak password:  Very similar words

Try a much stronger password, such as in the listing below:

<?php

// include class

include 'securepwd.inc.php';

// assume this is the password supplied by the user

$pwd = 'fy238%AWI';

// create object

$securepwd = new securepwd(true, true, true, true, 'parker', 5, 'passwords.txt');

// check password

if (!$securepwd->check($pwd)) {

      echo "Weak password: ". $securepwd->geterror();

} else {

      echo "Strong password";

}

?>

The check() method will now pass it without any fuss. The end result is a system that's harder to crack, and the user will have a higher level of security.

Testing password strength with ext/crack

An alternative to the securepwd class is PECL's ext/crack extension, which provides another way of verifying the password's strength. The ext/crack extension tests a password by running a dictionary attack on it. Here's an example of the extension in action:

<?php

// open dictionary handle

$dict = crack_opendict("/usr/local/share/cracklib/pw_dict") or die('Cannot create dictionary handle');

// assume this is the password supplied by the user

$pwd = 'prker9a^h2';

// check password

crack_check($dict, $pwd);

echo crack_getlastmessage();

// close dictionary handle

crack_closedict($dict);

?>

The crack_check() function checks the password against a word list, performs various other tests to determine the strength of the password, and returns a message indicating whether the password is acceptable.

Give it a try

As these examples illustrate, it's not particularly difficult to enforce password security in your Web application. You can decide to enforce password security by generating hard-to-crack passwords and assigning them to users or by testing the passwords supplied by users and only allowing them to proceed with the secure ones.

Try adding this feature to your next PHP application — I think you'll be pleasantly surprised by the results.

TechRepublic resources about password security

Editor's Picks

Free Newsletters, In your Inbox