Scripts are a great way to expand the inherently static nature of HTML and give your Web sites dynamic functionality, such as database content extraction. Of course, whenever data packets are moving back and forth, security risks are an unavoidable complication.
In this Daily Feature, I’ll look at my five top tips for securing your Apache Web server for use with the Common Gateway Interface (CGI), one of the more popular services for allowing servers to interact with external applications, such as scripts. I’ll use Red Hat Linux 7.2 server with Apache 1.3.24 for these examples, but the basic principles apply to any Linux/Apache configuration.
1. Use a ScriptAlias in your configuration
A tongue-in-cheek remark in one of the Apache FAQs says that you should consider not aliasing your script directory only if “you have no users, and nobody ever visits your server.” Allowing a user to run a CGI script arbitrarily from anywhere in the file system robs the system administrator of control and gives a malicious user a great opportunity to wreak havoc.
To address this risk, Apache provides the ScriptAlias directive in the httpd.conf configuration file, with the following syntax:
ScriptAlias aliasname "/path/to/cgi/directory"
A default Apache installation includes the following directive:
ScriptAlias /cgi-bin/ "/usr/local/apache/cgi-bin/"
This tells Apache that the directory /usr/local/apache/cgi-bin, where CGIscripts will live, should be accessible as http://server/cgi-bin. Scripts will not be able to be run from other locations.
The ScriptAlias directive is specific to a virtual host. If the directive is outside any VirtualHost directives, it defines the global CGI directory. If found inside a VirtualHost directive, the ScriptAlias directive specifies the CGI directory that should be used for that particular host.
Apache Virtual hosts
For more information on setting up Virtual hosts with Apache, check out Scott Lowe’s article “Apache's virtual servers allow you to set up multiple sites on one server.”
To allow users’ browsers to use CGI scripts under the public_html directory of their home directory, you could add the following to your httpd.conf file:
Allow from all
This tells Apache that any /home directory can use a cgi-bin and that the ExecCGI option allows the execution of CGI scripts from that directory.
2. Keep an eye on your CGI code
CGI programmers can open potentially devastating holes in your Web server environment. Keep in mind that a CGI is simply another program running on your server. If that program is poorly written or the writer simply makes an error that opens a hole, your system can be compromised.
To guard against even honest mistakes, make sure the system administrator is adept at identifying problems in a CGI. Sending all code through a peer review before being implemented is a good idea, too.
3. Run as separate users
By default, CGI scripts all run as the same user, normally the user that’s running the Web server. Since users can manage their own processes, a malicious script could be written to clobberanother CGI process or CGI database. Apache offers two approaches to let you force CGI processes to run as users different than root.
Since version 1.2, Apache has included suEXEC, a feature designed to allow you to run different CGI scripts as different users. To use suEXEC, you build it at the same time you install Apache by using the —enable-suexec parameter during the configure stage. Because the Apache folks want you to understand what suEXEC actually does, they also require you to provide at least one suEXEC configuration parameter. For my Apache installation, I used the configuration command shown in Listing A.
This command enables suEXEC and provides it with one parameter. In my example the parameter defines the location of the document root directory. The make and make install steps for the Apache installation also build the suEXEC executable and place it in /usr/local/apache/bin. To provide CGI scripts for user directories, you need to specify the parameter —suexec-userdir with the name of the directory (within a user’s home directory) where CGI scripts will reside.
Once you start Apache with the apachectl start command, suEXEC will load and write the message shown in Listing B to the error log.
Once suEXEC is operational, you can enable its use in one of two ways. If you have configured the —suexec-userdir parameter, you can force CGI scripts in a user directory to be run as that particular user by prefacing the user id with a ~ in the URL, as in: http://servername/~slowe. By adding the ~ character, you force Apache to run CGI scripts in the slowe home directory as the user slowe.
The second way to use suEXEC is to provide user and group directives inside a VirtualHost directive. These directives force CGI scripts to run as the user named instead of the primary Web server user.
Obviously, for this approach to work, the user must actually exist. As an added security precaution, suEXEC does not allow you to run scripts as the root user.
Like suEXEC, CGIWrap is a utility that allows you to run CGI scripts as another user (it’s available here). To install CGIWrap, download and expand the CGIWrap distribution.
For my installation, I used the configure script shown in Listing C.
The required httpd-user directive tells CGIWrap the user identity of the Web server. The second directive tells CGIWrap where the Web server’s cgi-bin directory is located. The installer will place the final executable in the users cgi-bin directory. Since the executable resides in the server’s primary cgi-bin directory, it’s important to allow only trusted users access to this directory. You should create other CGI directories, such as those underneath individual home directories.
4. Check your input at the door
A common problem with CGI scripts is that the script itself is weak in security checks. An unchecked buffer or input can create problems for you if a malicious user discovers such a flaw.
Let’s say I’ve just set up a Web site that asks users to provide me with their e-mail addresses. A user sends me the following text:
firstname.lastname@example.org;cd /;rm –rf *
This script then uses the address as the input of a commandfor some purpose, perhaps to send an e-mail. What happens next is bad. After the address, the system changes to the root directory and executes the command rm –rf *,effectively deleting everything on the hard drive. At this point reinstalling my server is my only option because this hacker just wiped out my system. In all the scripts you either write or you are asked to install on your Web server, make sure input is always carefully checked in order to avoid these types of problems.
5. Get rid of the sample scripts
Apache comes with two sample CGI scripts, printenv and test-cgi, but by default these scripts can’t be executed. Unfortunately, I have seen instances of a busy administrator putting dozens of scripts up all at once and executing the chmod +x * command from within the cgi-bin directory, forgetting that the sample scripts were still there.
This command added an execute permission to every script in the directory, including the sample scripts. I’ve made this error on my test system to show you the results. Browsing to http://192.168.1.100/cgi-bin/test-cgi on my test system yields the output shown in Listing D.
Fortunately, there’s not that much information here that would be useful to a potential hacker. However, Listing E shows the output from http://192.168.1.100/cgi-bin/printenv.
This information is much more valuable because it can give the hacker two pieces of critical information. First, the output in Listing D shows information about how the directory structure is designed. The line DOCUMENT_ROOT="/usr/local/apache/htdocs tells a hacker exactly where Apache is installed. This could be a huge problem if your security plan includes security through obscurity, and you’ve set up Apache in a non-default directory.
The second bit of critical information shows how usernames on your systems are composed. The line SERVER_ADMIN="slowe@director" shows a possible hacker that users on my system are named with first initial and last name. Again, any information that a hacker can get easily can spell bad news for your security.
Mitigating this risk is simple—just delete the default CGI scripts in the cgi-bin directory.
Only part of your plan
These five tips are only part of what should be a comprehensive security plan for your site. With CGI, make sure that the scripts that you place up on your site are reasonably secure and that they automatically check their input.
And as with any technology you plan on implementing in a publicly viewable system, you need to completely understand how CGI works before you put it in place. By misusing CGI scripts you run the risk of exposing your system, your data, and possibly your employees to malicious hackers and crackers.