the webmasterPassword-Protecting Areas of Your Web Site![]()
by Dave Taylor
Dave Taylor is president of strategic consultancy Intuitive
Systems, nestled in the Santa Cruz mountains above Silicon Valley. He
has been involved with UNIX since 1980. His latest book, Teach
Yourself UNIX in 24 Hours, can be previewed at
<www.intuitive.com/tyu24/>..
Password Protection, Take One The first and perhaps most obvious way to do this is to replace a page of information with a login FORM on a Web page, then feed what the user entered to a CGI script that compares the password against the official password for that area of the site. The HTML for the form might look like:
<FORM ACTION=login.cgi METHOD=post>
Then, if we're going to utilize a Perl solution and have something like the simple cgi-lib.pl library from Steven Brenner (you can get a copy for yourself from your local CPAN archive), the script underlying this is as simple as:
#!/usr/bin/perl
Enter the correct password ("unix", as defined in the fourth line of the Perl script) and you're in: The next page you'll see is "logged-in.html". This first version works, but it's pretty darn rudimentary and has some drawbacks, not the least of which is that everyone has the same password. Obviously, without account names to go with it, this is security only in the most minimal of senses.
There's another problem here too, one that's a bit more subtle: Once
you've logged in, the URLs you're seeing in your Web browser are
post-login URLs. If you were to send, say, the real-life URL of the
page we're talking about here --
<http://www.intuitive.com/CGI/ You'd be surprised how many sites use this kind of mechanism for password protection. One password for everyone just isn't very good. Having a password facade can be good for some cases, but isn't very secure. A Second Try Before we leave this area, however, an example of where this kind of login might be useful is when you have individual accounts and want to display different information based on the type of account. In this case, the wrinkle is that you need to ask for both an account and password pair on the FORM (a trivial change), extract both in the CGI script, and then compare them against a file of defined account/password pairs. In this case, let's create a file "pwfile" that contains two lines
taylor:unix:partner
that define the account name, password, and level of access granted. The second version of the Perl login script is a bit more complex. First, the subroutine that does all the work, reading and parsing the account file:
sub Matches
Here's where Perl is a winner: The split() routine automatically breaks up the line of information at the ':' separator, returning each of the three values into its own mnemonic variable. Then the conditional tests are easy to code. The main program needs to be modified to take advantage of the level of access that we can now grant:
#!/usr/bin/perl
Do you see what's happening here? If user "taylor" logs in successfully, he'll be dropped onto the Web page "partner.html," whereas if the guest user logs in, she'll start out on the "guest.html" page. This is a cool way to control access to a site and simultaneously offer multiple levels of access. It still suffers from some of the limitations of the earlier solution, of course. If you see "guest.html," you might well guess "partner.html" was another possible Web page, and poof, you're in! A Third Solution: Let the Server Do the Work Yet another solution, one that offers more security, is to let the Apache Web Server do the work through the .htpasswd facility. In essence, you create a simple password file containing names and encrypted passwords, then enable your Web server to look for the file. Once set up, any access to any files within the protected folder must automatically be validated by forcing the user to enter a login/password pair. To create the password file, I use a simple Perl script that I cobbled together called makepasswd:
#!/usr/bin/perl
As you can see, it does the work of encrypting the password and then displays exactly the information you'll need to add to the new .htpasswd file. A file duplicating the two accounts shown above would look like this:
taylor:z6K5hUINhVrIA
With the passwords encrypted, it's a lot harder for hackers to reverse-engineer and sneak in if they manage to snag a copy of this information! The only other step is to change the httpd.conf file so that the server knows to look for the password file in the directory. This is done by adding the boldface lines below to the file:
<VirtualHost www.intuitive.com>
Now we're rocking! Any access to any of the information in the specified folder (AuthName) requires the user to log in to the server correctly, with the dialog box (as shown in Figure 1) popped up and the account/password information compared against the contents of the AuthUserFile as shown above.
Figure 1 ![]() This is very cool and professional looking, being able to hide your information behind this kind of password protection. The downside is that you don't get much control over the presentation and appearance of the box, whereas in the previous approaches you could build a login page that looked very consistent with the rest of the site's appearance. Merging These Together Unfortunately, there's no easy way to include additional fields in the htpasswd file data (which would be ideal), so instead you're stuck having either to give out different password-protected URLs for different classes of users (for example, yourhost.com/partners/ and yourhost.com/guest/) or try a hybrid solution. Let's talk about the latter for a sec. It turns out that once you've logged in to a Web server with the .htpasswd-prompted solution, for the duration of that session you now have an additional environment variable that you're carrying around with you: REMOTE_USER. It'll contain the name half of the name/password information required to log in. With that in your toolbox, you could then have an index.cgi script, for example, that looks up the user in a second access-level file (keyed on the REMOTE_USER information), then presents a page based on that information. It's a simple subset of what we've already seen; we don't even need to worry about any CGI argument parsing. The first part is the replacement for the match routine:
sub AccessLevel
If there isn't a match in the file, it returns "guest" as the access level. Notice that I'm using the same file from the previous examples; it's living one level up on the filesystem (../pwfile) but otherwise it's as you've already seen. Finally, here's the simple snippet that's the heart of the switch CGI script:
$name=$ENV{"REMOTE_USER"};
The variable REMOTE_USER contains the login name of the person who successfully signed in to the restricted area. If I just signed in as "taylor" (with the password "unix") then REMOTE_USER would be set to "taylor" automatically. Summary There's no perfect, graceful solution to password-protecting an area of a Web site with complete control, but this does give you a good idea of the different types of solutions and their trade-offs. You can try out all these different solutions online and experience them for yourself: <http://www.intuitive.com/CGI/password/>.
|
![]() First posted: 14 Apr. 1999 jr Last changed: 14 Apr. 1999 jr |
|