21 December 2011
The Mysteries of Apache Passwords Revealed
If you’re reading this you probably already know that Apache has two primary authentication mechanisms: Basic and Digest. We have at times needs to manipulate these in Perl – either to directly work with a password file or for a database to be accessed by mod_auth_dbd (or one of its predecessors from older Apaches).
Update Feb 2025. Digest is trivial to crack with current tools and shouldn’t be used.
Digest has a single and very straightforward password format. Use the hexadecimal representation of the MD5 encryption of the the string “username:realm:password” where realm is your arbitrary digest authentication realm. In my article on deploying Catalyst with Starman I already provided this code to manage it:
use Digest::MD5 qw(md5 md5_hex md5_base64); my $authname = 'advent' ; my $user = 'billy' ; my $password = 'themountain' ; my $result = md5_hex( "$user:$authname:$password" ) ; say "$user:$authname:$result" ;
Basic is the more complex (and should only be used over a secured connection). Modern versions of the htpasswd utility use an algorithm that the documentation describes as “the result of … an iterated (1,000 times) MD5 digest of various combinations of a random 32-bit salt and the password.” The only example of the code is the C source for the module itself, and I lack the expertise to create a Perl Module to wrap it to or re-implement the algorithm in Pure Perl. I would like to tell you that someone already did that, but I can’t find it. Not to despair, it eventually sunk in that Basic Authentication supports at least 3 other methods of encoding a password. PlainText and old-fashioned Crypt aren’t very secure if our passwords file falls into the wrong hands. The third, is based on SHA1, which is stronger than the algorithm used by Digest, and there are Perl Modules existing to do the hard stuff.
Update Feb 2025. Digest::SHA1 does not support longer values, other modules on CPAN and Apache support SHA256 and SHA512.
use Digest::SHA1 qw(sha1 sha1_base64); my ( $realm, $user, $password ) = @ARGV ; my $sha1 = sha1_base64($password); say qq / User $user Password $password Result $sha1 ApacheSHA1 {SHA}$sha1= / ;
This is simple, and the new mod_auth_form module currently only works with basic authentication, so we need it.