6.4.2 Doing your own authentication (Cont.) - Page 9
July 3, 2002
Before trying it, we need to create the Users table. Here is a sample command:
CREATE TABLE Users (
username CHAR(12) NOT NULL,
password CHAR(13) NOT NULL,
name CHAR(30),
email CHAR(24),
PRIMARY KEY (username)
);
Don't worry about the name and email fields for now. They'll be used by a later
example.
We need to add a user to the table, along with an encrypted password. Suppose we
want the user to be named 'fred' with password 'tuesday'. We need the encrypted
string before we can add Fred.
MySQL has an encryption function, so if that's our database of choice (as shown
in the examples) we could use that. But I previously mentioned that Perl makes the
crypt function available if the operating system provides it, so let's look at a more
generic example:
The arguments for crypt are the string to encrypt and a two character salt value,
used by the algorithm in a way similar to the seed of a random number generator.
crypt returns a 13 character encrypted string whose first two characters are the salt
value. That's why the last block of code retrieved the encrypted password value from
the database first before validating the unencrypted test string. The encrypted value
was passed along with the test string to crypt which looks only at the first two characters
of the salt. Without the correct password and salt string it is mathematically
unlikely that crypt will generate a matching value. 5
To create a valid user entry then we need to first create a salt value and encrypt the
password with it. We could use any two characters for the salt (as long as they are letters,
numbers, or '.' or '/'), but it would be best to generate a random value for
each user. Here is a short Perl procedure from the Examples:: CreateUser module that
generates the salt and returns a string encrypted with it:
sub createPassword {
my $password = shift;
my @salts = ('a'..'z', 'A'..'Z', 0..9, '.', '/');
my $salt = join("", map {$salts[rand(scalar(@salts))]} (1,2));
return crypt($password, $salt);
}
We need to call this function with fred's password. Fortunately, Perl lets us concoct
scripts on the command line. By invoking the Examples:: CreateUser via the -M
switch we can call it like so:
perl -MExamples::CreateUser -e \
'print Examples::Createuser::createPassword("tuesday"), "\n"'
PQTpxFNiroTcU
Note that you need to either tell Perl where to find Examples:: CreateUser via the -I
switch or run the command from the directory which holds Examples, such as
/usr/local/apache/lib/perlin my example configuration.
Add user fred with the encrypted password to the database:
INSERT INTO Users VALUES ('fred', 'PQTpxFNiroTcU');
Now you should be able to log in as fred. Remember that the database user (web) and
password given in the example code have to be valid for the database, and the web
user must have access to the Users table.
The following examples will make use of createPassword in building a user
manager.
5. While it is important to keep the original password a secret, the salt string is less important. There are
4,096 possible salt values (64 choices for each of two characters), and while a human wouldn't want to
type them all in, a trivial program could find the right salt given the correct password.
6.4.3 Do I need SSL for this?
Whether you use HTTP authentication or write your own, you face the choice of
encrypting the login transaction or not. There are plenty of sites that don't, depending
on the situation and what is at risk:
- If the application and its users are protected behind a firewall, encryption is
probably not necessary. Conversely, business data which needs to be hidden
from employees' casual curiosity should not be on a web site.
- Encryption may be too expensive for high-traffic systems, especially if the user
data doesn't contain sensitive information. If you track only user preferences, for
example, you (and your users) probably aren't concerned about password theft.
- The HTTP authentication protocol includes another AuthType, digest, which
does not send passwords in clear text. If your users run browsers that implement
digest authentication, then you don't need to add the overhead of SSL. Unfortunately,
digest authentication isn't implemented dependably in browsers.
Obviously any e-commerce site which accepts credit cards, Social Security numbers,
or other important identifications should use SSL. If your site would be liable to a
suit were a user's data stolen, you must encrypt the channel or warn the user of the
risk. The simplest practical test is: what could happen to a user whose information is
stolen from this site? If your users could be harassed in some way, or your data would
help a criminal in committing a crime against them, you are obligated to protect
their information.
6.4.2 Doing your own authentication (Cont.) - Page 8
Web Development with Apache and Perl
6.5 User Management - Page 10
|