Chapter 17

How to Keep Portions of the Site Private


Security is a complex and controversial subject. Some people view system infiltrators as "freedom fighters of the information age," and some see cracking into systems as a test of technical skill, a cyber-rite of passage. Under most circumstances, however, penetrating a computer system without authorization is a crime. This chapter addresses the nature of the current threat and provides some guidelines for defense.

The first part of the chapter defines some terms and gives an overview of the major security threats. The rest of this chapter describes what a local Webmaster can do to keep her site secure. Chapter 40, "Site Security," takes up the topic of security again, discussing the larger issues of site security, security policy, and the Incident Response Team to show what a site administrator can do to keep a site safe.

An Overview of Security Terms

ISO Standard X.509 details nine threats that a computer network might face:

This chapter addresses defenses against masquerade and replay, with less emphasis on denial of service and data interception.

Identity interception is a fact of life with most network services. A user can participate in an exchange anonymously using special "anonymity servers" on the Net or by "spoofing" the e-mail system so they appear to be someone else. HTTP, the Web protocol, does not usually capture a user's name, so personal identity is safer with the Web than with most other services.

Manipulation and repudiation are easily prevented by using a digital signature system based on public keys. The public key system called PGP is described in this chapter. Chapter 29, "Fulfillment," describes a different system called Privacy Enhanced Mail, or PEM.

There are no good defenses against misrouting and traffic analysis. If an attacker can gain access to the bitstream (either on the local area network or by grabbing it from the Internet) he or she can change mail headers or perform traffic analysis. This chapter uses the terms "hacker" and "cracker" in their technical sense. Just as the term "gentleman" once had a precise meaning (a male of noble birth), so the term "hacker" was coined to refer to the most productive people in a technical project-people who often worked extremely long hours to add clever technical features. For a detailed history of hackerism as the term is used here, see Steven Levy's excellent book Hackers: Heroes of the Computer Revolution (Dell: 1984). The term "cracker" refers to a person who commits unauthorized penetrations of computer systems. The analogous term "phone phreak" refers to people who make similar penetrations into the telephone system.

Simple Privacy

It's often said, "If you want something kept secret, don't tell anyone." Files served up on the World Wide Web are far from secret. In general, anyone who knows the URL can view the page. From time to time, however, a Webmaster needs a middle ground-files that should be widely available but not available to everyone. For example, assume that a site promotes membership in a club or organization. Promotional materials are available to the general public, but certain files are part of what a member buys when he or she joins, so those files should be available only to members.

Security is not without cost. Figure 17.1 illustrates the fact that one can achieve security only at the expense of ease-of-use and performance. A Webmaster can choose any operating point within this triangle but cannot be at all three corners simultaneously.

Figure 17.1 : This is the security-performance-useability triangle.

One way to think about the tradeoff between security and user issues is to compare the value of the information and service provided by the server to the likely threat. Security analysts often identify six levels of security threat:

For most systems, the value of the information and service justifies securing the system against at least the first two or three levels of threat. It might be true that no system openly available on the Net can withstand a concerted attack from the highest levels of threat. In the late 80s, computer security experts agreed that most attacks came from curious or greedy users-often the technically gifted teenagers stereotyped by the movie War Games. These days, however, experts widely agree that the threat has grown more sophisticated. Attacks now are often committed by an uberhacker who is technically skilled, well-funded, and has strong motives for attacking a system. Indeed, the U.S. government has studied the topic of information warfare, a term that refers to the exploitation of computer infrastructure resources (such as those operated by banks, telephone companies, and transportation companies) by a hostile government.

This chapter presents a series of security solutions, ranging from simple user authentication systems sufficient to keep out the casual user who might inadvertently compromise security, to fairly expensive systems that raise the cost of penetration high enough that potential infiltrators need good funding in order to succeed.

See Chapter 40, "Site Security," to learn some techniques that might deter, or at least detect, the uberhacker.

Built-in Server Access Control

The easiest way to protect files is to use the access control mechanisms built into NCSA and similar servers. These techniques are not powerful-they can be foiled with very little effort. Nevertheless, they're easy to implement, and they keep confidential files away from most casual browsers.


The NCSA server looks for a file named access.conf in the configuration directory. Here are two typical entries for access.conf:

<Directory /usr/local/etc/httpd/htdocs/morganm> <Limit GET> order allow, deny allow from all </Limit> </Directory> <Directory /usr/local/etc/httpd/htdocs/jwandling> <Limit GET> order deny, allow deny from all allow from </Limit> </Directory>

These entries tell the server who has access to the morganm and jwandling directories, respectively. The first line of each entry names the directory. The next line shows that GET requests are restricted. The order directive specifies the order in which allow and deny directives should be applied. In the first example, GET requests are allowed to the morganm directory from any domain and denied from none. In the second example, the deny directive is applied first, so access is not allowed from anywhere. Then the allow directive is invoked, allowing access to the jwandling directory only from, as a exception to the general denial rule.


You can place the same entries shown above in access.conf in a file named .htaccess in the directory you want protected. This approach decentralizes access control. Instead of requiring the site Webmaster to manage access.conf, this approach allows each directory owner to set up localized security. To restrict access to the jwandling directory, for example, make a file named .htaccess (notice the period before the name-this makes the file invisible to casual browsers). Put the following lines in the file:

<Limit GET> order deny, allow deny from all allow from </Limit>

The same mechanism can be used to limit POST as well as GET.

User Authentication

The next step in site protection is user authentication. For example, to restrict access to the morganm directory to the specific users jean, chris, and mike, put the following lines in the access.conf file:

<Directory /usr/local/etc/httpd/htdocs/morganm>] Options Indexes FollowSymlinks AllowOverride None AuthUserFile /usr/local/etc/httpd/conf/.htpasswd AuthGroupFile /dev/null AuthName By Secret Password Only! AuthType Basic <Limit GET> require user jean require user chris require user mike </Limit> </Directory>

To do the same thing using an .htaccess file, use the following lines:

AuthUserFile /home/morganm/.htpasswd AuthGroupFile /dev/null AuthName By Secret Password Only! AuthType Basic <Limit GET> require user jean require user chris require user mike </Limit>

In both cases, AuthUserFile specifies the absolute pathname to the password file. The location of this file is unimportant, as long as it's outside the Web site's document tree. The AuthGroupFile directive is set to /dev/null-a way of saying that this directory does not use group authentication. The AuthName and AuthType directives are required and are set to the only options currently available in the NCSA server.


To create the password file that's specified by AuthUserFile, run the program htpasswd. This program does not always come with the server installation kit but is available from the same source. It must be compiled locally.

To run htpasswd the first time, type something like the following:

htpasswd -c /home/morganm/.htpasswd jean

The -c option creates a new password file with the specified pathname. The username (in this case, jean) specifies the first user to be put into the file. htpasswd responds by prompting for the password.

Your subsequent calls to htpasswd should omit the -c option:

htpasswd /home/morganm/.htpasswd chris htpasswd /home/morganm/.htpasswd mike

Once the password file is in place, it's easy to tell the server to read (or reread) the file. Run the following command:

ps -ef | grep httpd

On some versions of UNIX, ps -aux is the first command.

This command lists all the current copies of the Web server, something like this:

root 9514_1_0 16:55:45 - 0:00 /usr/local/etc/apache/src/httpd nobody 9772_9514_0 16:55:45 - 0:00 /usr/local/etc/apache/src/httpd nobody 11568_9514_0 16:55:45 - 0:00 /usr/local/etc/apache/src/httpd nobody 11822_9514_0 16:55:45 - 0:00 /usr/local/etc/apache/src/httpd nobody 12084_9514_0 16:55:45 - 0:00 /usr/local/etc/apache/src/httpd nobody 12338_9514_0 16:55:45 - 0:00 /usr/local/etc/apache/src/httpd

Look for the one that begins with root. Its process ID is used as the parent process ID of all the other copies. Note the process ID of that parent copy. For this example, it's 9514. Once you've obtained this number, enter the following line:

kill -HUP 9514

This command sends a hangup signal (SIGHUP) to the server daemon. On most processes, the hangup signal tells the server that an interactive user, dialed in by modem, has hung up. Daemons, of course, have no interactive users (at least not the sort who can get to them by modem), but by convention, sending SIGHUP to a daemon tells it to reread its configuration files. When the parent copy of httpd rereads access.conf, it learns about the new restrictions and starts enforcing them.

You can use similar techniques to set up authenticating groups, but requirements for group authentication are less common. See your server documentation if you want details.

Password-Protection Scripts

The built-in access control mechanisms are easy to set up and offer security against casual threats; however, they will not resist a determined attack. Anyone with certain types of network monitoring equipment can read the username and password out of the packets. If there's an ethernet LAN close to the server, for example, an ethernet card can be put into "promiscuous mode" and told to read all traffic off the network. For even lower cost, a determined cracker can often guess enough passwords to penetrate most sites. Some servers honor a GET request for .htaccess, giving the cracker knowledge of where the password file is kept. Even though the passwords are encrypted, methods exist to guess many passwords. Software is available to try every word in the dictionary in just a few minutes. A brute force search involving every word of six or fewer characters takes under an hour. Compromise of a site does not require compromise of every account-just one. Studies have found that, before users are taught how to choose and change passwords, as many as 50 percent of the passwords on a site fall victim to a simple cracking program. After training, about 25 percent of the passwords are still vulnerable.

Rules for choosing good passwords can be built into software. A password should be long (eight characters or more) and should not be any word appearing in a dictionary or related at all to the user's personal information. A password should not be the same as the username, or the same as any of the computer vendor's default passwords. The password should be entered in mixed case-or, better yet, with punctuation or numbers mixed in. Every user should change passwords regularly, and when a new password is chosen, it should not be too similar to the old password.

passwd+ is designed to replace the UNIX system's standard password maintenance program (/bin/passwd). It catches and rejects passwords following certain patterns-it rejects many for being too short or matching a dictionary word. Many newer versions of UNIX have incorporated logic similar to passwd+ into their own version of passwd; for Web site password protection, logic similar to passwd+ certainly could be incorporated.

It's important to make sure that passwords are written to the disk in encrypted form and that the file holding the passwords is read-protected. The following three listings provide the basis for a simple password protection system. Like .htaccess, this system is vulnerable to network sniffing and replay. Unlike .htaccess, however, this system can be extended to include passwd+-style logic, so that the passwords hold up better against crackers.

Listing 17.1 shows login.cgi. Connect an HTML form to login.cgi and use it to collect their name and password. If they present a valid name and password, the script redirects them to a file in the protected subdirectory. If they are the site owner (as evidenced by their $LEVEL being equal to two, they are redirected to the addUser.html page.

Listing 17.1  login.cgi-Checks a Visitor's Name and Password Before Allowing Him to Access the Site
#!/usr/bin/perl # login.cgi # Written by Bryan Kilian, 1995 # Modified by Michael Morgan, 1995 # Define Variables $passfile = '/path/to/the/file/.passwd'; read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); # Split the name-value pairs @pairs = split(/&/, $buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $value =~ s/<([^>]|\n)*>//g; $FORM{$name} = $value; } &error_name unless $FORM{'user'}; &error_pass unless $FORM{'pass'}; $keywewant=0; open(FILE, $passfile); while(<FILE>) { ($user,$passwd,$uid,$ulevel,$stuff) = split(/:/,$_); if ($user eq $FORM{'user'}){ $keywewant = $uid; } $USER{$uid} = $user; $PASS{$uid} = $passwd; $LEVEL{$uid} = $ulevel; chop($stuff); $STUFF{$uid} = $stuff; } close(FILE); &error_nouser if ($keywewant==0); $crypted=crypt($FORM{'pass'},'ZZ'); if ($crypted ne $PASS{$keywewant}) { &error_pass; } ($fullname,$office,$phone,$email) = split(/\,/,$STUFF{$keywewant}); print "Content-type: text/html\n\n"; if ($LEVEL{$keywewant}==2) { $destinationURL = "http://path/to/addUser.html"; } else { $destinationURL = "http://path/to/protected/file.html"; } print "Location: $destinationURL\n\n"; sub error_nouser { print "Content-type: text/html\n\n"; print "<H1>Sorry</H1>You seem to have specified an illegal username.\n"; print "Please try again.\n"; exit; } sub error_name { print "Content-type: text/html\n\n"; print "<H1>Sorry</H1>You seem to have left out the username field.\n"; print "Please try again.\n"; exit; } sub error_pass { print "Content-type: text/html\n\n"; print "<H1>Sorry</H1>Incorrect Password<br>"; print "Please try again.\n"; exit; }

User passwords are maintained with the script shown in Listing 17.2. When login.cgi recognizes the site owner and sends them to addUser.html, they supply the data for the new user.

Listing 17.2  addUser.cgi-Used by Site Owner to Authorize New Users to Use the Site
#!/usr/local/bin/perl # addUser.cgi # By Bryan Kilian, 1995 # Modified by Michael Morgan, 1995 # Define Variables $passfile = '/path/to/file/.passwd'; $superlevel = 2; read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); # Split the name-value pairs @pairs = split(/&/, $buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $value =~ s/<([^>]|\n)*>//g; $FORM{$name} = $value; } # ask for the new password twice--make sure they match if ($FORM{'pass'} ne $FORM{'again'}) { &error_pass; } # add any pattern-matching and logic against # weak passwords HERE &error_name unless $FORM{'user'}; &error_pass unless $FORM{'pass'}; &error_pass unless $FORM{'again'}; &error_who unless $FORM{'whouser'}; &error_fullname unless $FORM{'fullname'}; ($FORM{'office'} = '') unless $FORM{'office'}; ($FORM{'phone'} = '') unless $FORM{'phone'}; open(FILE, $passfile) || print "Could not open $passfile\n"; $biggest=0; $whouid=0; while(<FILE>) { ($user,$passwd,$uid,$ulevel,$stuff) = split(/:/,$_); if ($user eq $FORM{'user'}){ close(FILE); &error_dup; } if ($user eq $FORM{'whouser'}) { $whouid = $uid } $USER{$uid} = $user; $PASS{$uid} = $passwd; $LEVEL{$uid} = $ulevel; chop($stuff); $STUFF{$uid} = $stuff; if ($uid > $biggest) { $biggest = $uid }; } close(FILE); &error_who if ($whouid == 0); $test = crypt($FORM{'whopass'}, 'ZZ'); if ((crypt($FORM{'whopass'},'ZZ') ne $PASS{$whouid}) || ($LEVEL{$whouid} ne $superlevel)) { &error_illegal; } $biggest++; $USER{$biggest} = $FORM{'user'}; $PASS{$biggest} = crypt($FORM{'pass'}, 'ZZ'); $LEVEL{$biggest} = $FORM{'level'}; $STUFF{$biggest} = $FORM{'fullname'}.','.$FORM{'office'}.','.$FORM{'phone'}.','.$FORM{'email'}; open(FILE, ">$passfile"); foreach $key (sort keys(%USER)) { print FILE "$USER{$key}:$PASS{$key}:$key:$LEVEL{$key}:$STUFF{$key}\n"; } close(FILE); print "Content-type: text/html\n\n"; print "<HTML><HEAD><TITLE>User Added</TITLE></HEAD><BODY>"; print "<H1>User Added</H1><P>User : $FORM{'user'}<br>"; print "Name : $FORM{'fullname'}<br>User ID : $biggest"; print "<HR></BODY></HTML>\n\n"; sub error_who { print "Content-type: text/html\n\n"; print "<H1>Sorry</H1>"; print "Cannot find entering user.\n"; print "Please try again.\n"; exit; } sub error_illegal { print "Content-type: text/html\n\n"; print "<H1>Sorry</H1>"; print "You have specified an illegal password, or you are not of\n"; print " the correct user level\n"; print "Please try again.\n"; exit; } sub error_dup { print "Content-type: text/html\n\n"; print "<H1>Sorry</H1>You seem to have specified an existing username.\n"; print "Please try again.\n"; exit; } sub error_name { print "Content-type: text/html\n\n"; print "<H1>Sorry</H1>You seem to have left out the username field.\n"; print "Please try again.\n"; exit; } sub error_pass { print "Content-type: text/html\n\n"; print "<H1>Sorry</H1>There is a problem with the password fields."; print "Either you left one of them blank, or they do not match."; print "Please try again.\n"; exit; } sub error_fullname { print "Content-type: text/html\n\n"; print "<H1>Sorry</H1>You seem to have left out the Full Name field.\n"; print "Please try again.\n"; exit; }

To get started, write a one-line Perl program to encrypt a password. For example, if you want your password to be OverTheRiver, run the script in Listing 17.3.

Listing 17.3 the First Password
#!/usr/local/bin/perl # By Michael Morgan, 1995 $encryptedPassword = crypt("OverTheRiver", 'ZZ'); print $encryptedPassword; exit;

You get a reply like this one (the actual characters may vary):


Copy the encrypted password into the owner's line in the password file (shown below). After that, delete the program from the disk.

Each line of the password file should look similar. If the owner of the files is named Jones, for example, the owner's line might read as follows:

jones:ZZe/eiKRvN/k.: 1:2:I. M. Jones, (804) 555-1212, (804) 555-2345,

Once the first line of the file has been built by hand, the owner can add subsequent users by using the script.

If a cracker can get a copy of the password file, then he can run Crack or more sophisticated password crackers against it. Make sure that the password file is outside the document tree, forcing the cracker to test password guesses online. Next, add a counter to the script above, so that repeated attempts to access a user ID will disable that account and notify the system administrator.

Realize that these mechanisms do nothing to keep local users out of the site. Remember that on any system with more than a few users, a computer-assisted cracker can probably guess at least one password. Make sure that key files like source code and password files are readable only by those who absolutely must have access.

Vulnerability Due to CGI Scripts and SSIs

CGI scripts and SSIs bring vulnerability to the server. Many Webmasters believe that because the server runs as the unprivileged user nobody no harm can be done. But nobody can copy the /etc/passwd file, mail a copy of the file system map, dump files from /etc, and even start a login server (on a high port) for an attacker to telnet to. User nobody can also run massive programs, bringing the server to its knees in a denial of service attack.

Some administrators prefer to have CGI scripts run under the user ID of the person who wrote them, rather than under nobody. A program named cgiwrap enforces this rule, and makes a number of checks to decrease the likelihood that a script can do harm. There are others who argue that, if a security hole is present in a script, then allowing that script to run with the privileges of a real user is worse than having it run under nobody. Both arguments have merit-as the local Webmaster, you must decide whether or not cgiwrap is right for your site.

This site has cgiwrap available for download:

Whether or not you use cgiwrap, you should write CGI scripts to be as secure as possible. Consider the following Perl fragment, from a script to e-mail a form's contents to a user:

system("/usr/lib/sendmail -t $ownerAddress < $inputFile");

Here, $ownerAddress and $inputFile come from the HTML form. This snippet passes only one parameter to the system, so Perl starts a copy of the shell to process the line. One day, a cracker discovers the call to this script in the HTML form, and writes his own call:

<INPUT TYPE="hidden" NAME="userAddress" VALUE=";mail < /etc/passwd">

Even on a newer system that keeps encrypted passwords in a shadow password file, the cracker now has a list of the users on the system and can tell which ones have system-level privileges. He can use the gecos data in the /etc/passwd file as a starting point for guessing passwords. Of course, if the passwd file does contain encrypted passwords, then the cracker has an even more powerful starting point from which to crack one or more accounts.

There are two solutions to this problem-the best scripts use both. First, check the characters in any string that come from the user before the string is passed to the system. In Perl, use the following:

unless ($ownerAddress =~ /^[\w@\.\-]+$/) { &html_header("Bad Characters in Address"); # print out HTML here complaining about the bad characters print "The e-mail address contains illegal characters.\n"; &html_trailer; exit; }

Second, realize that the string is sent to the shell instead of being parsed internally-if the attacker is successful in getting a string to the shell, he or she can issue any command. Instead of using system(), the programmer could have done this:

open (MAIL, ">/usr/lib/sendmail -t"); print MAIL "To: $ownerAddress\n"; while (<STDIN>) { print $_; }

Because open never starts a shell, a cracker's attempt to send a command through $ownerAddress just raises an error message from sendmail.

The vulnerability described above is not unique to Perl-the same thing can happen in a compiled language. In fact, there's an additional vulnerability in compiled languages like C and C++. Suppose that a C programmer writes the following code:

int processFoo() { char buffer[10]; strcpy(buffer, readForm("foo")); /* do something with the buffer, which now contains the value of field _foo_ */ }

The programmer has reserved 10 bytes of memory to store the contents of the form variable foo. If the end user (either a legitimate visitor to the site or a cracker) enters more than the expected number of characters, the program might crash, leaving the system in a potentially vulnerable state.

A better design would be something like this:

#define kSizeOfFoo 9 int processFoo() { /* leave one room for null */ char buffer[kSizeOfFoo+1]; /* ensure that, no matter what comes up from the form, no more then 'kSizeOfFoo' characters are copied into the buffer. */ strncpy(buffer, readForm("foo"), kSizeOfFoo); /* do something with the buffer, which now contains the value of field _foo_ */ }

Perl has a built-in mechanism to help ensure that user-supplied data is not passed to the shell. In Perl 4, use the variant binary taintperl. For Perl 5, run this with the command-line option -T.

With taint turned on, Perl ensures that any variable set outside the program cannot affect anything else outside the program. For example, with taint turned on, Perl complains about the use of relative file names (since the PATH environment is set outside the script). The solution is either to use absolute pathnames or to explicitly take control of PATH:

$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin';

To use data from tainted variables to affect the world outside the script, extract patterns that are known to be safe. Here's an example:

$ownerAddress =~ /([\w-.]+\@[\w-.]+)/; $untaintedAddress = $1;

Communications Security

Web site security works like a home burglar alarm. You don't expect to make your site impregnable, but making it difficult to crack encourages crackers to move on to less fortified sites. Once the private parts of the site are password-protected, and the common CGI holes are closed, the remaining vulnerability at the Web-site level resides in the communications links between the user and the site. An aggressive cracker can sniff passwords, credit card numbers, and other confidential information directly from the Internet.

Credit card companies have led the effort to encrypt communications links. Credit card theft on the Internet is expected to follow a different pattern than theft in conventional transactions. When a physical card is stolen, thieves know that they have just a few days-maybe just hours-before the card number is deactivated. They try to run up as large a balance as possible while the card is still good. In so doing, they often trigger security software. If, on the other hand, a thief could get access to thousands of credit card numbers, then he could use each number just once. Such illegal use is unlikely to trip any credit card company alarms and, therefore, could lead to massive loss in the industry.

To put matters in perspective, many sites accept credit card numbers in the clear, but in a late 1995 thread on one of the HTML Writers Guild discussion groups, no one was able to document a single case of loss. Of course, if Internet credit card theft is following the low-density pattern described above, one does not expect loss to be detected or reported. In any case, as the size of the Web continues to grow-and the number of commercial transactions increases-it seems wise to provide protection for confidential information like credit card numbers.

Secure Socket Layer (SSL)

Most Webmasters are aware that Netscape Communications Corporation offers a secure server, the Netscape Enterprise Server (which is the successor to the Netscape Commerce Server). This product is based on Netscape's low-level encryption scheme, Secure Socket Layer (SSL). Recall from "Designing Faster Sites" (Chapter 4) the various layers of the communications stack. SSL is a Network layer encryption scheme. When a client makes a request for secure communications to a secure server, the server opens an encrypted port. The port is managed by software called the SSL Record Layer, which sits on top of TCP. Higher-level software, the SSL Handshake Protocol, uses the SSL Record Layer and its port to contact the client.

The SSL Handshake Protocol on the server arranges authentication and encryption details with the client using public-key encryption. Public-key encryption schemes are based on mathematical "one-way" functions. In a few seconds, anyone can determine that 7´19 equals 133. On the other hand, determining that 133 can be factored by 7 and 19 takes quite a bit more work. A user who already has these factors (the "secret key") can decrypt the message easily. Commercial public-key encryption schemes are often based on keys of 1,024 bits or more, which should require years of computation to crack. Using public-key encryption, the client and server exchange information about which cipher methods each understands. They agree on a one-time key to be used for the current transmission. The server might also send a certificate (called an X.509.v3 certificate) to prove its own identity.

In the Netscape browser, a key in the lower-left corner of the window shows whether a session is encrypted or not. A broken key indicates a non-secure session. A key with one tooth shows that the session is running on a 40-bit key. A key with two teeth shows that a 128-bit key is in use.

End users should not assume that seeing an unbroken key guarantees that their transmission is secure. They also should check the certificate. In Netscape Navigator, you can access this information by choosing View, Document Info. If the certificate is not owned by the organization the users think they're doing business with, they should verify the certificate by calling the vendor.

SSL was developed by Netscape Communications and is supported by their browsers and servers. Open Market has announced that they will support SSL in their HTTP server. A free implementation of SSL, named SSLeay, serves as the basis for security in Apache and NCSA httpd, as well as in Secure Mosaic.

SSL is documented at this Additional documentation on SSL is available at You can download the SSL library at Read the Frequently Asked Questions list at this site for more information on SSLeay:

SSL is a powerful encryption method. Because it has a publicly available reference implementation, you can easily add it to existing software such as Web and FTP servers. It's not perfect-for example, it doesn't flow through proxy servers correctly-but it's a first step in providing communications security.

Secure HTTP (S-HTTP)

A competing standard to SSL is Secure HTTP (S-HTTP) from Enterprise Integration Technologies. Like SSL, S-HTTP allows for both encryption and digital authentication. Unlike SSL, though, S-HTTP is an application-level protocol-it makes extensions to HTTP.

The S-HTTP proposal suggests a new document suffix, .shttp, and the following new protocol:

Secure * Secure-HTTP/1.1.

Using GET, a client requests a secure document, tells the server what kind of encryption it can handle, and tells the server where to find its public key. If the user who matches that key is authorized to GET the document, the server responds by encrypting the document and sending it back-the client then uses its secret key to decrypt the message and display it to the user.

One of the encryption methods available with S-HTTP is PGP, described in the next section.

Pretty Good Privacy (PGP)

The Pretty Good Privacy (PGP) application, written by Phil Zimmerman, has achieved fame and notoriety by spreading "encryption for everyone." For several years, PGP hung under a cloud since it did not have clear license to use the public-key encryption algorithms. There was also an investigation into whether Zimmerman had distributed PGP outside the United States. (U.S. law prohibits the distribution of strong encryption systems.)

Those clouds have finally lifted. With the release of PGP 2.6, the licensing issues have been entirely resolved, and the U.S. government has announced that it has no interest in seeking indictments against Zimmerman.

If you live in the U.S. and are a U.S. citizen or lawfully admitted alien, you can get PGP from the server at MIT. If you live outside the U.S., you should use PGP 2.6ui-this version was built in Europe and does not violate U.S. export control laws.

You can get PGP by visiting this at and following the instructions given.
You can get the latest European-built version of PGP from the virus/crypt/pgp/tools directory at Check out this site for more information on the commercial version of PGP

Part of the agreement with the patent-holder, RSA Data Security, Inc., was that PGP could not be used for commercial purposes. A commercial version of the program, with proper licensing, is available from ViaCrypt.

Although PGP is available on all common platforms, its user interface is essentially derived from the UNIX command line; in other words, it's not particularly user-friendly. The ViaCrypt version has addressed this concern to some extent, but it's still fair to say that only a very small percentage of users use PGP on a regular basis. If S-HTTP moves into the mainstream, more users might use PGP "behind the scenes" as the basis for session encryption.

One good use of PGP, apart from S-HTTP, is in dealing with information after a user has sent it to the server. Suppose that a hotel accepts reservations (with a credit card number to hold each reservation) over the Web. The hotel might use the Netscape Commerce Server to ensure that credit card data is not sent in the clear between the user and the Web site. Then, once the CGI script gets the credit card information, what can it do with it? If it stores it unencrypted on a hard disk, the numbers are vulnerable to a cracker who penetrates overall site security (as described in Chapter 40, "Site Security"). If the card numbers are sent in the clear via e-mail to a reservation desk, they risk being sniffed en- route over the Net.

One solution is to use PGP to transfer the reservation message (including credit card data) by secure e-mail. Start with a form mailer like Matt Wright's Find the place in that script where it opens a file handle to sendmail and change it to the following:

open (MAIL, "| /usr/local/bin/pgp -eatf reservations | mail") || &die("Could not open mail");

No user-supplied data has been passed to the shell. Now, put the reservations desk on the PGP public keyring. When the script runs, PGP encrypts (the -e option) the text (-t) from STDIN for user reservations into ASCII characters and adding armor lines (-a) to prevent tampering. The result is written to standard output because the filter option (-f) is turned on.

The reservations clerk must have his own copy of PGP (it's available for PCs, Macs, and other common platforms). When he receives the encrypted message, he decrypts it using his secret key, making sure to store the credit card data and other private information offline. (He can even save the encrypted message on his local disk, using PGP and a secret passphrase).

PGP allows the user to input a passphrase instead of a password. Passphrases can be arbitrarily long and may have embedded white space and other special characters. Take advantage of this flexibility to make the passphrase difficult to guess.

Going Further

There are several places you can turn for additional helpful information on the topics covered in this chapter.

You can get general information on public-key cryptography at

RSA, the company that holds the patents on public-key encryption technology, provides a Frequently Asked Questions list at this site: One of the original developers of encryption technology provides information at this site: You can get answers to all your questions about PGP at: See the files PGP.FAQ.1 through PGP.FAQ.4. If you're looking for a book on PGP, you'll find the application thoroughly described in PGP: Pretty Good Privacy by Simson Garfinkel (O'Reilly: 1995). General security tips await you at this site: This is a Frequently Asked Questions list addressing general security concerns: