[Image]
The Common Gateway Interface (CGI) is what, for now at least, makes the
World Wide Web interactive. CGI enables users to do more than simply read
static files; it enables them to perform tasks such as searching for
information, filling out and submitting forms, and more.
This capability makes the Web a far more useful place and has been widely
adopted by the Internet community. Throughout the universities,
laboratories, companies, and other organizations that comprise the Web, CGI
scripts are developed, refined, shared--and sometimes compromised.
For the Laboratory, too, CGI is a widely used tool. As always, and
especially at an institution such as the Laboratory, whenever you allow
somebody to execute tasks on your machine, you're opening a potential
security hole and you need to make sure it's adequately plugged.
The Mechanism
Basically, there are two parts to a CGI "script": an executable (the script
itself) and an HTML page that drives the executable. The executable can be
just about anything that runs, including system calls, Perl scripts, shell
scripts, and compiled programs (C, Pascal, etc.).
The HTML page is actually optional. CGI scripts can be used without user
input to increment page counters, display the day and date, etc. If the user
is to enter any information, however, the HTML page is needed.
When both parts are properly constructed, the CGI action is performed as
follows (as illustrated by a form submission):
1. The user pulls the HTML form page from the server onto his/her client
machine (see Figure 1).
2. The user fills out the form on the client machine.
3. The user presses "Submit", which then sends an execute request to the
server. (The client-side browser interprets the form into an execute
request, which identifies the server-side program and includes the
information that was filled into the form.)
4. The server executes the requested program.
[Image]
Figure 1: CGI Execution Cycle
The same basic process occurs for other CGI scripts that accept user input.
A clickable imagemap, for example, sends the image to the client machine and
issues an execute request that specifies which part of the image was clicked
on.
The fundamental strength of CGI is its simplicity. Entering information on
the form and all other manipulation is performed on the client machine, so
the server doesn't have to worry about it. All that the server has to do is
to execute the request when it is issued.
Therein also lies the fundamental security weakness within CGI. Because the
HTML page itself is transferred to the client machine, the user has an
unrestricted ability to edit the page at will and to enter whatever he/she
pleases. The execute request might easily be a good deal different from what
you expect.
A Simple Shell Breach
The most commonly cited examples of CGI security breaches involve cajoling
the shell into performing something unexpected. For instance, let's say we
want a form that lets a user e-mail a message to a specified person. In our
HTML form page, we might write something like the following:
Alan
Arkin
Lucille
Ball
George
Burns
Now let's say we execute a script that writes the message to a temporary
file and then e-mails that file to the selected address. In Perl, this could
be done with
system("/usr/lib/sendmail -t $send_to < $temp_file");
As long as the user selects from the addresses that are given, everything
will work fine. There is however no way to be sure. Because the HTML form
itself has been transferred to the user's client machine, he/she is free to
edit it to read something like
Alan Arkin
As soon as this gets sent, the original sendmail call will stop at the
semicolon, and the system will execute the next command--which would mail
the password file to the user, who could then easily decrypt it and use it
to gain login access to your machine.
Other Breaches
The above example is not the only thing that can go wrong. Aside from
capturing a password file, malicious users can also exploit poorly defended
CGI to
* Access other sensitive files;
* Install and execute their own programs on your system (including
"Trojan Horses" that monitor system activity and report back to the
user);
* Install other viruses; or
* Gain an overall map of your filesystem in order to search for potential
weaknesses.
Also, not all of the weaknesses are at the system level (and UNIX isn't the
only vulnerable operating system). Other vulnerabilities that have been
identified include the following:
* Certain mail programs allow a ~ to execute arbitrary programs.
* Server-side includes have been tricked into executing commands embedded
within HTML comments in the input (e.g., ).
* C programs that "forgot" array boundaries have been tricked into
executing programs via very long input.
* Some early sendmail programs allowed any user to execute arbitrary
programs.
This is by no means a complete list. More breaches have been identified;
others have been invented but not yet identified; still others have not yet
been invented. The basic point, however, remains the same: CGI should always
be used with caution.
How to Make Your CGI Secure
As with other areas of computer security, the basic idea behind securing CGI
is to understand the demonstrated and potential threats, to counter these
threats, and to monitor system activity for unusual events.
Start with an adequately secured server. This includes appropriate screening
at the router, turning off un-needed daemons, creating a non-privileged WWW
user and group, and restricting the file system. Additional precautions may
be required, depending upon the partition in which you are working, who the
intended audience is, and the sensitivity level of the data on the machine.
These precautions including monitoring who accesses the scripts and the
other activities those users perform, and consulting with your computer
security officer as needed.
Beyond the basics, there are other methods of improving CGI security.
Never Accept Unchecked Input
Always check for special characters such as ";" before you open a shell. You
can do this either by restricting the input you accept or by escaping any
dangerous characters. In Perl, for example, the following line escapes
dangerous UNIX shell characters within a variable:
$var =~ s/([;<>\*\|`\$!#\(\)\[\]\{\}:'"]@)/\\$1/g;
Among the other things to check:
* For server-side includes, check for "<" and ">" in order to identify
and validate any embedded HTML tags.
* For scripts that utilize e-mail, validate that the addresses are within
an acceptable domain (e.g., make sure they're "@lanl.gov").
* Look for any occurrence of "/../" (which might indicate that the user
is attempting to access higher levels of the directory structure).
* For selection lists, check to make sure that the value sent is a valid
choice.
Prefer Compiled Programs to Interpreted Scripts
This is a very general guideline, by no means an ironclad "rule." The basic
idea is that a compiled program (e.g., a binary executable from C) is more
difficult to make sense of if a user is able to get a copy of it. This in
turn makes it more difficult for the user to search for potential weaknesses
within the program.
Counterbalancing this general preference are the facts that an interpreted
program (e.g., Perl) is generally easier for the programmer to understand
(including whoever has to support the program after it is written) and
easier to test (no need to compile before each test). Hence, even though the
compiled programs are generally preferred, there are many specific cases
where the interpreted program is perfectly acceptable.
Avoid the Shell
Again, this is a very general guideline--more of a caution than a rule.
There is nothing inherently wrong with opening a shell, provided that the
security implications are understood and addressed. Frequently, though, it
is easier to sidestep the shell concerns and call a program directly.
In UNIX/Perl, for example, a new shell is opened by system, exec, eval,
backticks, etc. Hence, the basic weakness of the following line (taken from
the above example) stems from the fact that it is operating at the system
level in its own shell:
system("/usr/lib/sendmail -t $send_to < $temp_file");
A construction like the following sidesteps this weakness by calling
sendmail directly:
open(MAIL, "|/usr/lib/sendmail -t");
print MAIL "To: $send_to\n";
print MAIL "$input_line_1";
...etc.
close(MAIL);
Keep in mind, however, that when you call a program directly you are in a
sense trading the known security vulnerabilities of the shell for the
potentially unknown vulnerabilities of the program.
Control Filesystem Permissions
Users need to execute CGI scripts, but there is no reason for them to have
read or write permissions. Similarly, users need to read the HTML driver
files (and to read and execute their directory), but there is no need for
them to have write or execute permission to the files (or write permission
to their directory).
These controls are most easily maintained as follows:
* Put scripts in separate directory and set permissions for the directory
and its files to rwx--x--x (or the equivalent).
* If you are using compiled programs, put the source in a different
directory from the compiled programs (to prevent users from "guessing"
their name and accessing the source).
* Do not leave old or not-yet-validated versions of scripts in the active
scripts directory (including the filename~ backups that Emacs
automatically makes).
* Restrict permissions for HTML files to rw-r--r-- and for their
directories to rwxr-xr-x (or the equivalents).
* If the CGI output will be written to a file, put that file in a
separate directory, assign that directory's ownership to the
non-privileged WWW user, and set (umask) the permissions to rw-------
for the file and rwx------ for the directory.
Validate Scripts from the Web
There are many CGI scripts freely available on the Web. While these can
often serve as a good starting point, many of them come from university
environments that do not have the same security concerns as the Laboratory.
A number have been demonstrated to contain security holes, and some have
even been found to contain Trojan Horses.
Any time you "borrow" a free script as a starting point, make sure to
validate it for security. Check it as outlined above, and modify it as
needed. Above all, don't run anything that contains any lines you don't
understand. Don't even test it until you've figured it out--there's no
telling what it might do.
Additional Information
As CGI programming has become more popular, the amount of information about
it and security has grown. Good sources of information (including the
sources of some of the above suggestions) include the following:
* The CGI authoring newsgroup (news:comp.infosystems.www.authoring.cgi)
* Lincoln Stein's "WWW Security FAQ"
(http://www-genome.wi.mit.edu/WWW/faqs/www-security-faq.html)
* Paul Phillips' "Safe CGI Programming"
(http://www.cerf.net/~paulp/cgi-security/safe-cgi.txt)
* Michael Van Biesbrouk's "CGI Security Tutorial" (a
href="http://csclub.uwaterloo.ca/u/mlvanbie/cgisec/">http://csclub.uwaterloo.ca/u/mlvanbie/cgisec/)
Links to these and other security resources are available from the
Information Architecture's Internet/WWW Subject Area web space--
http://www.lanl.gov/projects/ia-lanl/areas/int-web/
For further information about the Information Architecture project itself,
see
http://www.lanl.gov/projects/ia/
Or look under "What's New" from the Laboratory home page.
----------------------------------------------------------------------------
Tad Lane, tad@lanl.gov, (505) 667-0886
Information Architecture Standards Editor
Communications Arts and Services (CIC-1)
----------------------------------------------------------------------------
ia-std-editor@lanl.gov - Copyright © 1996 UC - Disclaimer - March 12, 1996
Unlimited release - LALP-96-11 (2/96)
Back to CGI Security Compilation