Increasingly, many companies and individuals are web-enabling their
applications via differing methods, ranging from commercially available
products to home-grown solutions. No matter what method is used, it is
important to focus consistently on at least one area: security.
Regardless of the software or methodology you use to connect your
applications to the web with the CGI specification, the following tips
should be adhered to in order to ensure a good level of security for your
software and data.
Basic CGI Security Tips
- Never trust data from any remote field for use as a command to be
executed locally. Doing so leaves you open to command injection via
shell meta-characters (ie., ";rm -rf *;"). If you -absolutely MUST- rely
on client-originated data to obtain commands to run, they should be
thoroughly scanned and rejected with prejudice if they contain shell
meta-characters. This is an absolute last resort. The primary goal is
to -never- trust client-originated data to give you commands to execute
locally.
- Never accept requests that provide fields you did not expect. This
is indicative of someone using your software inconsistently with your
forms, which means it is likely spoofed. Likewise, never accept requests
that omit fields you do expect. Note that buttons of the "submit" type may
or may not show up, depending on the browser in use on the remote end, and
the way the form is submitted. Some browsers allow you to hit return in
INPUT TEXT fields, causing the browser to omit the submit button. If
the submit button is used, however, the button value will be submitted as
data as well. Allow for submit buttons as optional fields.
- When using hidden fields for internal use, always check to make sure that
each field matches a potential hardwired or server-provided value. Reject
any requests with unexpected hidden field values. Use hidden fields as
sparingly as possible, relying instead on session identification methods
combined with local data storage and retrieval.
- If re-displaying client-originated data via server-parsed HTML files,
always eliminate server-side-include (SSI) directives from the data before
utilizing it. Not doing so could allow malicious injection of arbitrary
commands from remote sites.
- Never use promiscuous modes on temporary files. Never make files world
writable, and try to limit the read modes as far as possible to avoid
local data interception, alteration, or deletion. Set the umask at the
beginning of your program to ensure the highest security possible, and
only specifically loosen any modes on files that absolutely need to be
more broadly available.
- Never use default non-httpd-specific environment variables, including $HOME,
$PATH, etc. Doing so relies on an environment that could possibly be
tainted, or just plain not what you expect. Have the CGI set its own
environment variables for use by subordinate processes. It is preferable
to explicitly call system commands by their full pathnames rather than
relying on $PATH, but if you must use $PATH, make sure you set it from
the CGI. As with being logged in as root, it is highly inadvisable to
include '.' in the path.
- Never rely on HTTP_REFERER as an absolute verification that a program
(like an email script) has been run from your site. This variable is
easily spoofed from the client end, and is simply not trustworthy.
- Never send passwords (system- or application-based) from the server to
the client in plain-text. Use encryption or digital signatures. In
general, the best policy is to always let the client side do as much of
any authentication as possible, and have the server provide as little
authentication data going outwards as possible. Avoid using field or
cookie names like "password", or equally obvious authentication-related
names, even when using encryption, digital signatures, or the like.
- When handling file uploads, never trust the original filename from the
remote system. Always use locally generated safe filenames for storage,
and only save the original remote filename for reference, if necessary.
Even when using them only for reference, any harmful injections like SSI's
or shell meta-characters should be eliminated from original filenames.
Store received files outside of the scope of the publicly available
document root directory unless they are specifically intended to be
redistributed via plain HTTP requests. Ensure that you change the mode
of any received file to something secure.
- If an application is not meant to be accessible to the world, protect
it in a suitable fashion. There are numerous methodologies for doing
so, including HTTP Basic Authentication, application-level user
authentication, network address acceptance/denial, etc. Utilize the
most appropriate methods for your application.
- If your application sends email, take steps to ensure that it may only
send to limited, intended recipients. Do not let your program turn the
system into an open mail relay.
- Never provide more information to the client about the server than is
absolutely necessary. This includes pathnames, system usernames,
passwords, actual application names, and other operating system and
application information. Putting a "powered by" label on your result
pages is tantamount to labeling your site, "Please crack me!" If proper
precautions are not taken, this kind of advertising makes it that much
easier for someone to cause havoc with current or future exploits for
that application.
- Never rely exclusively on client-side languages to ensure data integrity.
Not all clients may have the intended client-side language enabled.
Additionally, spoofed requests bypass such measures entirely. Always
check the integrity of your data at the application level on the server.
Client-side checks are to be considered a convenience to prevent
accidental data mis-entry, not a safeguard against corrupt or malicious
data.
- When using languages like C, never assume anything about the size of
the data coming in from the client-side. Buffer overruns are a major
security risk. Dynamically allocate memory, and specifically store
set amounts of data (ie, use strncpy() instead of strcpy()).
- Never assume that your application is safe from tampering simply because
your site employs SSL encryption. Do not confuse transport-layer
tampering with application-level data tampering. Malicious or corrupt
data can be sent as easily over an encrypted connection as it can over
a non-encrypted connection. A common mis-perception is that SSL "makes
everything safe". This is incorrect. SSL only makes the transport of
the data safe. The remote user is capable of altering whatever data
they like, at-will, prior to transport.
- Never assume that only your intended audience will use your software.
Anyone can dissect an HTML form and spoof a request utilizing the
information contained within, altering whatever data they like in the
process. Never assume that your application will always be used in
the intended fashion. Harden your application against unexpected
input.
- If your queries contain information you would rather not have present
in system logs (if they do, you should probably review the points in
this document to make sure you're doing everything you can to eliminate
risks), use the POST method rather than GET, as the contents of POST
queries are not logged by httpd.
- NEVER run httpd as root. Always run httpd as a non-privileged user. If
possible, run the CGI and children as yet another non-privileged user to
minimize the potential damage should either httpd or your CGI application
be compromised.
- If you make the choice to run httpd as the user that an application
requires, realize that if httpd is ever cracked, any files and/or data
that is owned by that same user-id is readily compromised. It is
recommended that one use 'suExec' (integrated with Apache), or my personal
preference, 'cgiwrap' (http://cgiwrap.unixtools.org/) to let your
applications run as a separate user from httpd itself. Additionally,
if this step is taken and your CGI is somehow cracked, files owned by
the user-id that httpd uses cannot be compromised.
- If regular users are allowed to create their own CGI scripts to use from
their own directories on the same system, realize that by default they
will run as the same user as httpd, If you do not take steps (like
using 'cgiwrap' and -enforcing- the use of it to isolate user-id's of CGI
programs between users and preventing the use of direct CGI calls by users
without a wrapper, any regular user's CGI (which may or may not be a
secure program) can potentially compromise the security of your own CGI
files and data, no matter how careful you were in the design of your
own software integration solution.
- Make sure any third-party CGI programs added to your system conform to
the high levels of security outlined above, so as to not undermine your
own security efforts.
Last Modified: 12/13/03