Web servers are designed to receive anonymous requests from unauthenticated hosts on the Internet and to deliver the requested information in a quick and efficient manner. As such, they provide a portal into your computer that can be used by friend and foe alike.
No piece of software is without its risk. Web servers, by their nature, are complicated programs. Furthermore, many organizations use Web servers with source code that is freely available over the Internet. Although this means that the source code is available for inspection by the organization, it also means that an attacker can scan that same source code and look for vulnerabilities.
The ability to add functions to a Web server through the use of CGI scripts tremendously complicates their security. While a CGI script can add new features to a Web server, it can also introduce security problems of its own. For example, a Web server may be configured so that it can only access files stored in a particular directory on your computer, but a user may innocently install a CGI script that allows outsiders to read any file on your computer. Furthermore, because many users do not have experience in writing secure programs, it is possible (and likely) that locally written CGI scripts will contain bugs allowing an outsider to execute arbitrary commands on your system. Indeed, several books that have been published on CGI programming have included such flaws.
Because of the richness of its tools, the plethora of programming languages, and the ability of multiple users to be logged in at the same time from remote sites over a network, the UNIX operating system is a remarkably bad choice for running secure Web servers. Because many PC-based operating systems share many of these characteristics, they are also not very good choices. Experience has shown that the most secure Web server is a computer that runs a Web server and no other applications, that does not have a readily accessible scripting language, and that does not support remote logins. In practice, this describes an Apple Macintosh computer running MacHTTP, WebStar, or a similar Web server. According to recent surveys, such computers comprise as many as 15% of the Web servers on the Internet.
Of course, there are many advantages to running a Web server on a UNIX computer instead of a Macintosh. UNIX generally runs faster than MacOS on comparable hardware, and UNIX is available for hardware platforms that run faster than PowerPC-based computers. Furthermore, it is generally easier for organizations to integrate UNIX-based Web servers with their existing information infrastructure, creating interesting possibilities for Web offerings. Finally, more MIS professionals have familiarity with building UNIX-based Internet servers than with building MacOS-based ones. Nonetheless, we suggest that the security-conscious administrator give the Mac-based approach serious thought.
To build a secure Web server on any platform, you must be able to assure a variety of things, including:
Network users must never be able to execute arbitrary programs or shell commands on your server.
CGI scripts that run on your server must perform either the expected function or return an error message. Scripts should expect and be able to handle any maliciously tailored input.
In the event that your server is compromised, an attacker should not be able to use it for further attacks against your organization.
The following sections explore a variety of techniques for dealing with these issues.
Most Web servers are designed to be started by the superuser. The server needs to be run as root so it can listen to requests on port 80, the standard HTTP port.
Once the server starts running, it changes its UID to the username that is specified in a configuration file. In the case of the NCSA server, this configuration file is called conf/httpd.conf. In the file, there are three lines that read:
# User/Group: The name (or #number) of the user/group to run httpd as. User http Group http
This username should not be root. Instead, the user and group should specify a user that has no special access on your server.
In the example above, the user changes his UID to the http user before accessing files or running CGI scripts. If you have a CGI script that is to be run as superuser (and you should think very carefully about doing so), it must be SUID root. Before you write such a script, carefully read Chapter 23.
NOTE: Do not run your server as root! Although your server must be started by root, the http.conf file must not contain the line "User root". If it does, then every script that your Web server executes will be run as superuser, creating many potential problems.
Web servers are complicated pieces of software. They use many files in many directories. The contents of some directories are made available over the network. The contents of other directories must not be made available over the network, and, for safety, should not be readable by users on your system. To run a secure server, you must understand the purpose of each directory, and the necessary protections that it must have.
The NCSA sever has six directories:
Directory | Purpose |
---|---|
cgi-bin | Holds CGI scripts |
conf | Holds server configuration files |
htdocs | Holds Web documents |
icons | Holds Web documents |
logs | Records server activity |
support | Holds supplemental programs for the server |
Many sources recommend creating a user called www and a group called www which can be used by the Web administrator to administrate the Web server:
drwxr-xr-x 5 www www 1024 Aug 8 00:01 cgi-bin/ drwxr-x--- 2 www www 1024 Jun 11 17:21 conf/ -rwx------ 1 www www 109674 May 8 23:58 httpd drwxrwxr-x 2 www www 1024 Aug 8 00:01 htdocs/ drwxrwxr-x 2 www www 1024 Jun 3 21:15 icons/ drwxr-x--- 2 www www 1024 May 4 22:23 logs/
This is an interesting approach, but we don't think that it adds much in the way of security. Because the httpd program is run as root, anybody who has the ability to modify this program has the ability to become the superuser. This is a particular vulnerability if you should ever move the server or configuration files onto an NFS-exported partition. Therefore, we recommend acknowledging this fact, and setting up your Web server directory with root ownership:
drwx--x--x 8 root www 1024 Nov 23 09:25 cgi-bin/ drwx------ 2 root www 1024 Nov 26 11:00 conf/ drwxr-xr-x 2 root www 1024 Dec 7 18:22 htdocs/ -rwx------ 1 root www 482168 Aug 6 00:29 httpd* drwxrwxr-x 2 root www 1024 Dec 1 18:15 icons/ drwx------ 2 root www 1024 Nov 25 16:18 logs/ drwxr-xr-x 2 root www 1024 Aug 6 00:31 support/
Notice that the cgi-bin directory has access mode 711; this allows the httpd server to run programs that it contains, but it doesn't allow a person on the server to view the contents of the directory. More restrictions make probing for vulnerabilities more difficult.
Inside the conf directory, the NCSA server has the following files:
File | Purpose |
---|---|
access.conf | Controls access to the server's files. |
httpd.conf | Configuration file for the server. |
mime.types | Determines the mapping of file extensions to MIME file types. |
srm.conf | Server Resource Map. This file contains more server configuration information. It determines the document root, whether or not users can have their own Web directories, the icon that is used for directory listings, the location of your CGI script directory, document redirections, and error messages. |
Because the information in these files can be used to subvert your server or your entire system, you should protect the scripts so they can only be read and modified by the superuser:
-rw------- 1 root wheel 954 Aug 6 01:00 access.conf -rw------- 1 root wheel 2840 Aug 6 01:05 httpd.conf -rw------- 1 root wheel 3290 Aug 6 00:30 mime.types -rw------- 1 root wheel 4106 Nov 26 11:00 srm.conf
Besides the setting of permissions, you may wish to enable or disable the following configuration options:
Most Web servers will automatically list the contents of a directory if a file called index.html is not present in directory. This feature can cause security problems, however, as it gives outsiders the ability to scan for files and vulnerabilities on your system.
Some servers allow you to follow symbolic links outside of the Web server's document tree. This allows somebody who has access to your Web server's tree to make other documents on your computer available for Web access. You may not want people to be able to do this, so don't enable the following of symbolic links. Alternatively, you may wish to set your Web server's symlinks "If Owner Match" option, so that links are followed only if the owner of the link matches the owner of the file that it points to.
Server-side includes are directives that can be embedded in an HTML document. The includes are processed by the HTML server before the document is sent to a requesting client. Server-side includes can be used to include other documents or to execute documents, and output the result.
Here are two sample server-side includes that demonstrate why their use is a bad idea:
<!--#include file="/etc/passwd">
<!--#exec cmd="rm -rf /&;cat /etc/passwd">
The first include provides an attacker with the contents of your /etc/passwd file, allowing them to wage a password-cracking attack. The second launches a background process that attempts to delete every writable file on your computer. Then it provides the attacker with a copy of your /etc/passwd file.
Fortunately, server-side includes must be specifically enabled on most Web servers. They are normally turned off.
Some servers, such as the NCSA server, allow you to limit processing of server-side includes to specific directories. The NCSA server uses the Options directive to control includes. Specify the option Includes for all server-side includes; specify the option IncludesNOEXEC to specify textual includes but to disable the execution of commands.
NOTE: Server-side includes should never be enabled for script directories. This is because it is possible that a script will output something that the user has typed, and the Web server will attempt to interpret the output, giving an attacker the ability to include arbitrary files or to execute arbitrary commands.
[1] The difference between programs and scripts is not always simple to discern, and the terms are not used consistently by everyone. We define a program to be code that must be compiled and linked before execution, and a script as a program that is usually interpreted without first being compiled into binary.
Writing a secure CGI script has all of the same problems as writing a secure SUID program or network server, plus many more. That's because there can be unexpected interactions between the Web environment, the Web server and the CGI script, creating problems with the combined system where no problems obviously were present in any single part. Therefore, we recommend that you read Chapter 23 before you embark on writing CGI scripts.
In addition to the information that we describe in that chapter, there are additional issues in writing programs for the World Wide Web.
Most security holes are not intentional. Nonetheless, the more people who have the ability to write scripts on your Web server, the greater the chance that one of those scripts will contain a significant flaw.
Do not allow users to place scripts on your server unless a qualified security professional has personally read through the scripts and assured you of their safety.
HTML includes the ability to display selection lists, limit the length of fields to a certain number of characters, embed hidden data within forms, and specify variables that should be provided to CGI scripts. Nevertheless, you cannot make your CGI script depend on any of these restrictions. That is because any CGI script can be run by directly requesting the script's URL; attackers do not need to go through your form or use the interface that you provide.
Be especially careful of the following:
If you create a selection list, the value that is returned for the input field will not necessarily match the allowable values that you have defined.
If you specify a maximum length for a variable, the length of the variable that is provided to your script may be significantly longer. (What would your script do if provided with a username that is 4000 characters long?)
Variables that are provided to your script may have names not defined in your script.
The values for variables that are provided may contain special characters.
If you use cookies or special hidden tags to maintain state on your server, your script may receive cookies or tags that it never created.
Attackers are by definition malicious. They do not follow the rules. Never trust anything that is provided over the network.
One of the reasons that it is surprisingly easy to create an unsecure CGI script is that it is very difficult to test your scripts against the wide variety of HTTP clients available. For example, most client programs will "escape," or specially encode, characters such as the backquote (`), which are specially interpreted by the UNIX shell. As a result, many CGI programmers do not expect the unencoded characters to be present in the input stream for their applications, and they do not protect their scripts against the possibility that the characters are present. Nevertheless, it is easy for the characters to be in the input stream, either as the result of a bug in a particular Web browser or, more likely, because a malicious attacker is attempting to subvert your CGI script and gain control of your server.
Check all values that are provided to your program for special characters and appropriate length.
By all values, we mean all values. This includes the contents of environment variables, host addresses, host names, URLS, user-supplied data, values chosen from selection lists, and even data that your script has inserted onto a WWW form through the use of the hidden data type.
Consider the case of a CGI script that creates a series of log files for each host that contacts your WWW server. The name of the log file might be the following: logfile/{hostname}. What will this program do if it is contacted by the "host" ../../../../etc/passwd.company.com? Such a script, if improperly constructed, could end up appending a line to a system's /etc/passwd file. This could then be used as a way of creating unauthorized accounts on the system.
Many programming languages, including C, ksh, sh, csh, and Perl, provide the means to spawn subprocesses. You should try to avoid using these features when writing CGI scripts. If you must spawn a subprocess, avoid passing through any strings that are provided by the user. If you must pass strings from the user to the subprocess, be sure that it does not pass shell meta characters including the `$|;>*<&> characters.
It is generally better to specify a list of allowable characters than to specify a list of dangerous characters. If you forget to specify an allowable character, there is no real harm done. But if you forget to specify a dangerous character, such as a backquote, you can compromise the security of your entire system.
If you are writing a CGI script that allows a user to send mail, use the /usr/lib/sendmail program to send the mail, rather than /bin/mailx or /usr/ucb/mail. The reason is that /usr/lib/sendmail does not have shell escapes, whereas the other mailers do.
Here is a bit of Perl that you can use to send mail securely. It bypasses the shell by using exec ( ) with a fixed string to run /usr/lib/sendmaildirectly:
open (WRITE, "|-") || exec ("usr/lib/sendmail", "-oi," "-t") || die "Can't fork$!\n": print WRITE "To: $address\n"; print WRITE "Subject: $subject\n"; print WRITE "From: $sender\n"; print WRITE "\n$message\n.\n"; close(WRITE);
There are many commands in Perl that will run the shell, possibly without your knowledge. These include system ( ), eval ( ), pipes, backquotes, and, occasionally, exec ( ) (if shell meta characters are present on the command line).
If you are using the Perl programming language, you can use Perl's "tainting" facility to track information that has been provided by the user. Perl marks such information as "tainted." The only way to untaint information is to match it using a Perl regular expression, and then to copy out the matched values using Perl's string match variables.
For example, if you have a name that has been provided by the user, you can untaint the value to be sure that it only contains letters, numbers, commas, spaces, and periods by using the following Perl statements:
$tainted_username =~ m/([a-zA-Z. ]*)/; $untainted_username = $1;
You can use the following to extract an email address:
$tainted_email =~ /([\w-.%]+\@[\w.-]+)/; $untainted_email = $1;
There are two ways to enable tainting. If you are using Perl 4, you should invoke the taintperl command instead of the Perl command, by placing the following statement (or something similar) at the beginning of your file:
#!/usr/local/bin/taintperl
If you are using Perl version 5, you accomplish the same result by using the -T flag:
#!/usr/local/bin/perl -T
Most Web servers can be configured so that all CGI scripts must be confined to a single directory. We recommend this configuration, because it makes it easier for you to find and examine all of the CGI scripts on your system. We do not recommend the practice of allowing any file on the Web server with the extension ".cgi" to be run as a CGI script.
Instead, we recommend that you:
Configure your Web server so that all CGI scripts must be placed in a single directory (typically, the directory is called cgi-bin).
Use a program such as Tripwire (see Chapter 9, Integrity Management) to monitor for unauthorized changes to these scripts.
Allow limited access to this directory and its contents. Local users should not be allowed to install or remove scripts, or to edit existing scripts without administrative review. You also may want to prevent these scripts from being read, to prevent someone from snooping.
Remove the backup files that are automatically generated by your editor. Many system administrators use text editors such as Emacs to edit scripts that are in place on the running server. Frequently, this leaves behind backup files, with names such as start~ or create-account~. These backup files can be executed an attacker, usually with unwanted results.
Throughout this book, we have railed against the practice of security through obscurity - the practice of basing some of the security of your system upon undocumented aspects. Nevertheless, the fact remains that the ready availability of UNIX source code, as opposed to the relative "obscurity" of the source code for other operating systems such as VMS or Windows/NT, means that potential attackers can search through the operating system looking for avenues of attack, and then craft their attacks in such a way as to guarantee the maximum possible access. One good way to prevent these sorts of attacks is to limit the access to source code.
Because it is so easy to make a mistake when writing a CGI program, it behooves sites to keep your CGI scripts and programs confidential. This does not guarantee security for buggy scripts: a determined attacker can still probe and, frequently, find flaws with your system. However, it does significantly increase the work that is involved. Determined attackers will still get through, but casual attackers may move on to other, more inviting systems.
Prevent network users from reading the contents of your CGI scripts. This will help keep an attacker from analyzing the scripts to discover security flaws. This is especially important for scripts that are written inside your organization, and thus might not be subject to the same degree of certification and checking as scripts that are written for publication or redistribution.
Many sites use the same directory for storing documents that are accessed through anonymous FTP and the World Wide Web. For example, you may have a directory called /NetDocs on your server that is both the home directory of the FTP user and the root directory of your Web server. This would allow files to be referred to by two URLS, such as http://server.com/nosmis/myfile.html or ftp://server.com/nosmis/myfile.html.
The primary advantage of HTTP over FTP is speed and efficiency. HTTP is optimized for anonymous access from a stateless server. FTP, on the other hand, had anonymous access added as an afterthought, and requires that the server maintain a significant amount of state for the client
Mixing HTTP and FTP directories poses a variety of security issues, including:
Allowing anonymous FTP access to the HTTP directories gives users a means of bypassing any restrictions on document access that the Web server may be providing. Thus, if you have confidential documents stored on your Web server, they may not remain confidential for long with this arrangement.
If an attacker can download your CGI scripts with FTP, he can search them for avenues for attack.
You must be very sure that there is no way for an FTP user to upload a script that will be run on your server.
The /etc/passwd file present for your FTP service might be visible to someone using the WWW service, thus leading to a compromise of its contents. If you have included any real passwords in that file, they will be available to the client for remote password cracking.
There are many other measures that you can take to make your server more secure. For example, you can limit the use of the computer so that it is solely a Web server. This will make it harder for an attacker to break in to your server and, if an attacker does, it will limit the amount of damage that he can do to the rest of your network.
If you do chose to make your server a stand-alone computer, read over Chapter 21, Firewalls, for a list of techniques that you can use to isolate your computer from your network and make the computer difficult for an attacker to use. In particular, you may wish to consider the following options:
Delete all unnecessary accounts.
Do not NFS mount or export any directories.
Delete all compilers.
Delete all utility programs that are not used during boot or by the Web server.
Provide as few network services as possible.
Do not run a mail server.
Another option, but one that may require a non-trivial amount of work, is to place your WWW server and all files in a separate directory structure. The WWW server is then wrapped with a small program that does a chroot ( ) to the directory (see Chapter 22, Wrappers and Proxies). Thus, if some way is found to break out of the controls you have placed on the server, the regular filesystem is hidden and protected from attack. Some WWW servers may have this approach included as an install-time option, so check the documentation.