HostedDB - Dedicated UNIX Servers

-->
Internet Security Professional Reference:CGI Security
Previous Table of Contents Next


Alternatives to SSI

Alternatives to SSI are available that achieve the same or very similar effects. In some cases they are less convenient.

Preprocessing Files

If SSIs are being used to include static files or other time-insensitive information, it is worth considering turning off SSI and simply preprocessing the documents. A comprehensive document management system should have facilities for this. For example, the canonical copy of a document might contain directives for the document system that indicate which files should be included. When it outputs HTML for use by the server, it includes those files at that time, requiring no further processing by the server.

Periodically Updating Files

Cron or a similar facility for periodically running programs can be used to update files. This is both more secure and more efficient.

For example, a cron job that updated all files once per hour would run only two dozen times a day and avoid server processing of the document every time it was requested. Most dynamic information is not so time-critical that it needs to be updated on an up-to-the-second basis.

Language Issues

Programming languages vary widely in their propensity to yield robust and secure code. In general, the higher level the language used, the lower the likelihood of an exploitable bug, but the slower the code will run. Often performance is of low or no importance when running CGIs, because they might run only a few times a day or perform an extremely simple task.

PERL

Overall, PERL is extremely well suited to CGI programming—it is portable, powerful, concise, extremely fast for an interpreted language, and has built-in security checks, described later. It dynamically extends data structures, rendering illegal memory references impossible. A number of convenient CGI libraries exist.

One downside is that an interpreter must be available to run PERL scripts, and this conflicts with the goal of minimizing the availability of powerful tools to server processes. A PERL script can be made to dump a core file after its internal compilation phase, and undump can be used on the core file to create a platform-specific executable not dependent on the presence of an interpreter. This is not available on all platforms and is wasteful of disk space, but it is presented as an option. See the PERL man page for more details.

Taint Checks

When executing a SUID script, or anytime the -T option is used, PERL maintains a concept of tainted and untainted variables. A tainted variable is one that was obtained externally in some manner; command-line arguments, environment variables, and the standard input stream (the three ways of passing data to a CGI) are all tainted. Furthermore, any variable that incorporates or references a tainted variable itself becomes tainted.

Tainted variables cannot be used in any command that spawns a shell, modifies files, or alters other processes. This is a tremendous aid to secure programming. The vast majority of security holes present in PERL CGI scripts would have been flagged very early if run with taint checks enabled. Variables can be explicitly untainted if the programmer is confident of their contents.

The -T switch enables other security checks as well. For instance, if the PATH environment variable is not explicitly set, it does not allow execution of any external programs. See the perlsec (PERL security) man page for more information on taintedness.

Other Built-In Tools

The -w switch turns on PERL warnings, a highly verbose set of checks that flag deprecated practices, unrecommended code, and lines where PERL is probably not doing what you think it is. Although not as likely to find security problems as taint checks are, warnings are still useful for this purpose, and all CGIs should be run with both switches before being made publicly available.

Another excellent tool during development is the strict module, enabled by the directive use strict. Errors are generated if the programmer tries to use any of a number of unsafe practices involving references, variables, and subroutines.

Invoking the Shell

There are a number of ways to execute external commands via the shell; taint checks usually catch careless errors but are not a panacea.

A shell is normally invoked in one of four ways:

  system: system(“command $args”);
  pipes: open(OUT, “|command $args”);
  backticks: ‘command $args’;
  exec: exec(“command $args”);

In addition, syscall and the file globbing operator can execute shell commands, but they should normally not be used this way.

A high degree of care should be used with all of these. The safest way is to ensure that any user-supplied input is composed only of desired characters. For example:

    unless($args =~ /^[\w]+$/) {
        # Print out some HTML here indicating failure
        exit(1);
    }

Because \w matches only word characters (alphanumerics and underscores) this exits unless $args is composed only of words. A less safe mechanism is to look for unsafe characters explicitly:

    if($to =~ tr/;<>*|‘&$!#()[]{}:’”//) {
        # Print out some HTML here indicating failure
        exit(1);
    }

As is probably clear in the second regular expression, it is easy to miss a shell metacharacter. The former method reflects the policy “that which is not explicitly allowed is rejected,” whereas the latter reflects “that which is not explicitly rejected is allowed.” The first policy is safer in all cases.


Tip:  An effect similar to C’s popen call can be achieved in PERL without using the shell by using a combination of open and a call to exec with a list argument, like this:

open(FH, ‘|-’) || exec(“command”, $arg1, $arg2);

This forks a new process and enables the parent to send data to it via the FH filehandle, with no shell ever involved.



Previous Table of Contents Next