CGI and Perl

Server Configuration Options

Servers running under multi-user machines will ordinarily "run as" some particular userid. The administrator will often create a faux userid to implement this.

Caution:

The server should never run under any administrative userid that has special permissions on the server or, for that matter, any other user's ID. Period.


Under UNIX, the httpd will ordinarily be started by the superuser and will then change to the userid specified in the server's httpd.conf for each new connection. The directive within the access.conf file to configure the server's user permissions may look like the following if the administrator has decided to run the httpd under the commonly used nobody userid:

# User/Group: The name (or #number) of the user/group to run httpd as.
 User nobody
 Group nobody

It is a simple task to make this entry into the httpd.conf, but what if it ever changes? You might want to inspect the value for this parameter once in a while to make sure your httpd is running under the UID you want it to. This will serve as a nice way to introduce the features of the HTTPD module and some of its capabilities. The HTTPD::config module is available at any CPAN archive.

use HTTPD::Config;
 $conf =  `/usr/local/etc/httpd/conf';
 @files = qw(httpd.conf);
 $config = new HTTPD::Config (SERVER => NCSA,
                              SERVER_ROOT => $conf,
                              FILES => [@files]);
 print "The current userid and group for httpd: ",
         $config->user, " , ",  $config->group,"\n";

As you can see, the HTTPD module provides a method for each configurable parameter within the httpd.conf file. Assuming that the user and group for your httpd are nobody and nogroup, respectively, the preceding script prints the following:

The current userid and group for httpd: nobody , nogroup

For this example, we've parsed only the httpd.conf file, but the HTTPD module allows you to parse any or all of the configuration files for the httpd.

This example is easily extended to print a nice report for any or all of the current values for the configurable parameters in the httpd configuration files. Some of the more important ones can be displayed with the following script:

use HTTPD::Config;
 $conf =  `/usr/local/etc/httpd/conf';
 @files = qw(httpd.conf srm.conf access.conf);
 $V= new HTTPD::Config (SERVER => NCSA,
                              SERVER_ROOT => $conf,
                              FILES => [@files]);
 print "Userid: ", $V->user,"\n";
 print "Group: ", $V->group,"\n";
 print "Administrator is: ", $V->server_admin,"\n";
 print "Running at port: ", $V->port,"\n";
 print "Access filename: ",$V->access_file_name,"\n";

This gives:

Userid: nobody
 Group: nogroup
 Administrator is: wmiddlet@adobe.com
 Running at port: 80
 Access filename: .privaccess

We'll be developing this example further using the HTTPD module to keep an eye on the directory-specific parameters a bit later. First, though, we need to take a look at a few more relevant issues. (For this example and others to follow, I used an unreleased version of HTTPD:: config. By the time you read this, the released version will be available in Doug MacEachern's CPAN directory.)

Other security issues to consider when configuring a server under UNIX include the following options:

  • Server-Side Includes: This is a common feature of many servers, but enabling it is something to consider carefully. It's possible, for instance, for an unsavory individual to arrange to make the password file on your server available to anyone through the use of a Server-Side Includes directive. These directives are especially dangerous if they can direct the server to execute a given command within the directive. The capabilities of server-side includes varies from server to server, but enabling anything but the ability to include files within the archive-tree (htdocs) is generally discouraged. (Includes NOEXEC) Server-side includes can, and should, be enabled on a per-directory basis. Given this fact, you should never enable them in cgi-bin directories.
  • Symbolic Links: Some servers will automatically follow a symbolic link if you enable them to do so. This, then, is another feature to consider carefully before enabling it. The option that allows links to be followed only if they belong to the same user as the link is generally a good one to turn on. (Sym Links If Owner Match)
  • User Directories: Most servers include the configuration item that enables the general URL http://yourhost.com/~username to work. Enabling this feature implies that each user on the server can create a directory in his or her home directory, usually called public_html, within and beneath which users can create their own archive of files to be served by extending the ~username URL. Enabling this feature simplifies the administrative hassles of creating a separate directory under the master archive for each user who wishes to populate his or her own space, but also creates the potential for unwary users to create holes. Another aspect and configuration option related to this capability and the symbolic-links capability is the "If Owner Match" option, mentioned previously, which instructs the server to follow symbolic links only if the file that is pointed to is owned by the same userid as the link that points to it.
  • Automatic Directory Listings: (Indexes) Turning this option on will allow the client to receive a listing of the directory if it contains no index.html. This is a convenient and widely used option but should be enabled with care. Allowing the client to know about every single file in the directory may introduce a security hole by giving the client access to files that are not intended to be seen. Things like emacs backup files, symbolic links created for your convenience, and other types of temporary files, as well as source code, may be unfit for public consumption. Always be sure to clean up carefully when working within the DocumentRoot.

So, given all of the configuration options available to protect your server within the httpd configuration files, we can use Perl to help ensure we haven't overlooked anything and that the important variables we've mentioned are set according to our preference. The HTTPD module gives us this capability. The following script builds on our previous simple examples and gives additional information on the directory-specific configuration options discussed in the preceding list:

use HTTPD::Config;
 $conf =  `/usr/local/etc/httpd/conf';
 @files = qw(httpd.conf srm.conf access.conf);
 $V= new HTTPD::Config (SERVER => NCSA,
                              SERVER_ROOT => $conf,
                              FILES => [@files]);
 print "Userid: ", $V->user,"\n";
 print "Group: ", $V->group,"\n";
 print "Administrator is: ", $V->server_admin,"\n";
 print "Running at port: ", $V->port,"\n";
 print "Access filename: ",$V->access_file_name,"\n";
 print "User Directory: ", $V->user_dir,"\n";
 print "Global Types:\t", join("\n\t\t",$V->add_type);
 print "\n\n";
 foreach $dir (keys %{$V->{`Directory'}}){
     print "Options for Directory: $dir\n";
     while(($opt,$val) = each %{$V->{`Directory'}{$dir}{`OPTIONS'}}){
         print "\t",$opt, " : ", @{$val},"\n";
     }
     print "\n";
 }

Which gives the following output:

Userid: nobody
 Group: nogroup
 Administrator is: wmiddlet@adobe.com
 Running at port: 80
 Access filename: .privaccess
 User Directory: public_html
 Global Types:   text/x-server-parsed-html .shtml
                 application/x-httpd-cgi .cgi
 Options for Directory: /usr/local/etc/httpd/cgi-bin
         Options : None
         AllowOverride : None
 Options for Directory: /usr/local/etc/httpd/htdocs
         order : allow,deny
         Options : Indexes FollowSymLinks
         allow : from all
         AllowOverride : All

Now this example has developed into a fairly useful script, which could be run, perhaps nightly, and compared to some known preferences. If anything has changed, either accidentally or otherwise, in your site's configuration, you can take action immediately.

You'll notice from the preceding output that two additional types have been enabled to allow CGI scripts anywhere via the .cgi extension and server-side includes or server-side parsing via the .shtml extension. As mentioned previously, these options should be considered very carefully before enabling them in the first place.

If you're using the Apache server, there are some additional configuration directives you might be interested in; one in particular is called AddHandler. As of the writing of this chapter, the HTTPD module doesn't automatically create a method to dump these out because they're a fairly recent feature for Apache httpd servers. Their intent is to configure the Apache server to use a dynamic module (akin to a Perl5 extension) to handle certain types of requests, as opposed to a CGI script or some other mechanism. In order to get at their settings and since we don't have a built-in method yet, we'll cheat a bit and access the HTTPD object's instance variables directly to extend the previous script to handle the additional parameter:

use HTTPD::Config;
 $conf =  `/usr/local/etc/httpd/conf';
 @files = qw(httpd.conf srm.conf access.conf);
 $V= new HTTPD::Config (SERVER => Apache,
                              SERVER_ROOT => $conf,
                              FILES => [@files]);
 print "Userid: ", $V->user,"\n";
 print "Group: ", $V->group,"\n";
 print "Administrator is: ", $V->server_admin,"\n";
 print "Running at port: ", $V->port,"\n";
 print "Access filename: ",$V->access_file_name,"\n";
 print "User Directory: ", $V->user_dir,"\n";
 print "Global Types:\t", join("\n\t\t",$V->add_type),"\n";
 print "Global Handlers:\t", join("\n\t\t\t",@{$V->{AddHandler}});
 print "\n\n";
 foreach $dir (keys %{$V->{`Directory'}}){
     print "Options for Directory: $dir\n";
     while(($opt,$val) = each %{$V->{`Directory'}{$dir}{`OPTIONS'}}){
         print "\t",$opt, " : ", @{$val},"\n";
     }
     print "\n";
 }

Now we get the complete output for our Apache server:

Userid: nobody
 Group: nogroup
 Administrator is: wmiddlet@adobe.com
 Running at port: 80
 Access filename: .privaccess
 User Directory: public_html
 Global Types:  text/x-server-parsed-html .shtml
                 application/x-httpd-cgi .cgi
 Global Handlers:        cgi-script .cgi
                         server-parsed .shtml
                         byte-serve  .pdf
 Options for Directory: /usr/local/etc/httpd/cgi-bin
         Options : None
         AllowOverride : None
 Options for Directory: /usr/local/etc/httpd/htdocs
         AddType : text/html .shtml
         order : allow,deny
         Options : Indexes FollowSymLinks
         allow : from all
         AllowOverride : All

This output indicates that there are three handler modules configured for our Apache server, and they each have specific extensions that trigger them. Note how we created the HTTPD::Config object using the value Apache for the SERVER parameter. As mentioned, we also accessed the HTTPD object directly via the $V->{`AddType'} reference, which pointed at an array. Ideally, we would submit a patch to the author of the HTTPD module so that the preferred mechanism would work.