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.
The 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