CGI Security Documentation

CGIWrap Tips and Tricks

This page collects configuration ideas, deployment shortcuts, rewrite examples, and access-control suggestions contributed by administrators working with CGIWrap in real environments. The focus here is not the basic installation path, but the practical refinements that make CGIWrap easier to hide behind clean URLs, easier to integrate with Apache and other servers, and safer to expose in production.

These examples are especially useful because they show how CGIWrap can be made more transparent to end users while still preserving the underlying wrapper model. They also highlight an important point: once CGIWrap is installed, much of the user experience depends on how the server administrator chooses to route URLs, protect debugging endpoints, and map user script locations.

Configuration Ideas and Practical Tricks

The material below preserves contributed examples and notes while organizing them into clearer sections. Most of these tips revolve around Apache, URL rewriting, built-in handlers, alternate server configuration styles, and ways to restrict access to the more revealing debugging variants of CGIWrap.

Apache mod_rewrite

Transparent URL Rewriting with mod_rewrite

One of the most useful ideas in CGIWrap deployment is rewriting CGIWrap URLs so the wrapper remains invisible to the end user. This can make user CGI paths look cleaner while still routing requests through cgiwrap, cgiwrapd, or the NPH variants underneath.

The first example below shows basic rewriting for virtual hosts in the form username.domain.com, where user CGI directories live under ~/cgi/. The rules keep the main CGI bin intact while translating friendlier paths into explicit CGIWrap calls.

Ok, here's a few examples on how you can use mod_rewrite to rewrite your 
CGIwrap URL's in a way that is totally transparent to the end user.

Example #1 - Basic Rewriting of CGIwrap URL's

In this example all VirtualHosts are in the format username.domain.com
All user's CGI directory's are ~/cgi/

In httpd.conf :-

# I control the Scope of these Rewrite with a VirtualHost Directive
# I dont want these rewrites to apply to the Main VHost, only to the customers
# VHosts (which are also rewritten)

<VirtualHost 192.168.0.1:80>

# set up scriptaliases for the man cgi-bin
ScriptAlias /cgi-bin/ /path/to/main/cgi-bin/

# Init out rewrite engine
RewriteEngine On
RewriteMap lowercase int:tolower

# keep the main CGI bin intact
RewriteCond %{REQUEST_URI} !^/cgi-bin/

# make the requested vhost lowercase in case some doofus uses wierd caps
RewriteCond ${lowercase:%{HTTP_HOST}} ^[a-z-][-0-9]+\.domain\.com$
RewriteRule ^(.+) ${lowercase:%{HTTP_HOST}}$1 [C]

# do the magic
RewriteRule ^([a-z-][-0-9]+)\.domain\.com/cgi/(.*) /cgi-bin/cgiwrap/$1/$2 [PT]
RewriteRule ^([a-z-][-0-9]+)\.domain\.com/cgi-d/(.*) /cgi-bin/cgiwrapd/$1/$2 [PT] 
RewriteRule ^([a-z-][-0-9]+)\.domain\.com/nph-cgi/(.*) /cgi-bin/nph-cgiwrap/$1/$2 [PT]
RewriteRule ^([a-z-][-0-9]+)\.domain\.com/nph-cgi-d/(.*) /cgi-bin/nph-cgiwrapd/$1/$2 [PT]

<VirtualHost>

The second example goes further by using RewriteMap. As the original note explains, map-based rewriting can be faster than ordinary regexp-based rewriting because mod_rewrite caches each map lookup until the map file changes.

Example #2 - Rewriting with a RewriteMap

RewriteMap's are alot faster than standard regexp based rewrite because
mod_rewrite caches each map lookup, until the mtime of the mapfile changes,
thus removing the needs for interpratation of the Rules each time they are
requested

This is a complete example, as used on our production webserver
()

# Again use a VirtualHost directive to control the scope
<VirtualHost 165.90.18.194:80>
ScriptAlias /cgi-bin/ /s101/current/cgi-bin/
RewriteEngine On
RewriteMap lowercase int:tolower

# map file which contains key/value information for all our customer
# subdomains (username.server101.com) and any domains they host with us
# map file is of format
# username.server101.com /s101/home/user
# domain.com /s101/home/user
# www.domain.com /s101/home/user
RewriteMap vhost dbm:/etc/apache/hostmap

# map file which contains key/value information for path info for customers
# cgi 
# format:
# username.server101.com /cgi-bin/cgiwrap/
# ...
RewriteMap cgi   dbm:/etc/apache/cgimap

# keep our CGI bin intact
RewriteCond %{REQUEST_URI} !^/cgi-bin/

# Other Aliases we have that we want to stay intact
RweriteCond %{REQUEST_URI} !^/icons/
RewriteCond %{REQUEST_URI} !^/cgi/
RewriteCond %{REQUEST_URI} !^/stats/images/

# we dont want the machine's name to be rewritten or even attempt to be
# rewritten as a failed map lookup will cause a pass through of the main vhost
RewriteCond ${lowercase:%{HTTP_HOST}} !^launch.server101.com$ [NC]

# heres where the magic starts
RewriteCond ${lowercase:%{HTTP_HOST}} ^(.+)$
RewriteCond ${vhost:%1} ^(/.*)$
RewriteRule ^/(.*) %1/$1

# Ok with the handling of the user vhosts/domains out of the way we can get on
# to the CGI stuff
# all our users personal cgi's are ~/cgi/
RewriteCond %{REQUEST_URI}  ^/cgi/

# keep the global cgi-bin intact still
RewriteCond %{REQUEST_URI} !^/cgi-bin/

# and our other aliases
RewriteCond %{REQUEST_URI} !^/icons/
RewriteCond %{REQUEST_URI} !^/stats/images/

# here we go again...
RewriteCond ${lowercase:%{HTTP_HOST}} ^(.+)$
RewriteCond ${cgi:%1} ^(/.*)$
RewriteCond ^/cgi/(.*)$ %1/$1 [PT]

<VirtualHost>

and thats it. We dont allow access to any of the *cgiwrapd's as they give out a
little more info than we want our users to have access to...

comments/corrections
--
Apache 1.1+ Handlers

Using Apache Built-In Handlers

Another approach is to use Apache’s built-in handler support instead of explicit rewrite rules. This can make CGIWrap more transparent, especially when users simply upload .cgi files and do not need to know that a wrapper is involved underneath.

<shane>
Actually, if you use Apache 1.1 (recently released), you can use their
built-in handlers like:

AddHandler cgi-wrapper .cgi
Action cgi-wrapper /virtual-path-to-wrapper/username

Of course, this requires all cgi's to end in '.cgi' but there is no need
to force the cgis to remain in one directory (as long as you compile the
wrapper to believe cgi's are in the user's root html directory).

I have my server configured to disallow all CGIs, so users are forced to
use the wrapper...works better than I had ever expected.  They can do
anything with their web sites - and none of them realize the wrapper
is in use.
</shane>
Netscape Server

Netscape Server Example

CGIWrap was not limited to Apache-only discussion. The following example shows a simple object configuration idea for Netscape server environments.

<oneiros>
For netscape server in obj.conf:
NameTrans fn="pfx2dir" from="/cgi" dir="path_to_cgiwrap" name="cgi"
NameTrans fn="pfx2dir" from="/cgid" dir="path_to_cgiwrapd" name="cgi"
-----
</oneiros>
Security Debug Access

Restrict Access to cgiwrapd and nph-cgiwrapd

One of the more important security notes on this page is that cgiwrapd and nph-cgiwrapd can reveal information about the web server installation that you may not want to make generally available. The example below uses Apache <Location> directives to restrict who can use those debugging endpoints.

<seth>
cgiwrapd and nph-cgiwrapd provide information about the installation of
your web-server that you might not want to make generally available.
Using the <location> directive under Apache 1.1 (or greater) it
is possible to restrict who is allowed to use these two debugging
versions of cgiwrap.

For example:

<Location /cgi-bin/cgiwrapd>
Order deny,allow
Deny from all
Allow from <your ip number here>
</Location>

<Location /cgi-bin/nph-cgiwrapd>
Order deny,allow
Deny from all
Allow from >your ip number here>
</Location>    

Depending on what value you place for allow from, you can control how
widely these debugging versions
are available.
</location></seth>
Apache UserDir

Rewriting ~/user/cgi-bin Paths

Another contributed example shows how Apache rewrite rules can translate paths like /~user/cgi-bin/program into explicit CGIWrap execution paths. This keeps user-facing URLs familiar while still routing them through the wrapper.

<yuji>
Look at the Rewrite rules.  You will need to activate mod_rewrite
and recompile (see the Apache documentation and Configuration file:
you will need to uncomment the follwing line and recompile.

Module rewrite_module      mod_rewrite.o
)

For an example of the runtime configuration, in the srm.conf you could
have: 

RewriteEngine on
RewriteRule  ^/~([^/]+)/cgi-bin/(.*)    /cgi-bin/cgiwrap/$1/$2 [PT] 
RewriteRule  ^/~([^/]+)/cgi-bin-d/(.*)  /cgi-bin/cgiwrapd/$1/$2 [PT] 
RewriteRule  ^/~([^/]+)/nph-bin-d/(.*)  /cgi-bin/nph-cgiwrapd/$1/$2 [PT] 
RewriteRule  ^/~([^/]+)/nph-bin/(.*)    /cgi-bin/nph-cgiwrap/$1/$2 [PT] 

Which translates  /~user/cgi-bin/program to
 /cgi-bin/cgiwrap/user/program. Also (in this example) 
 /~user/cgi-bin-d/program is translated to
 /cgi-bin/cgiwrapd/user/program, to provide debugging
support.  And so on... 

The setup of cgi-wrap will determine where the scripts actually reside.
(and I would actually put the script in a directory NOT in the
usual public_html tree, because then it is possible for an anonymous user
to read the cgi scripts).

I have not implemented this to support virtual domains separately, but
it should be possible.
</yuji>
Action VirtualHost

Action-Based Execution and the ScriptAlias Requirement

The final example expands on Action-based execution and calls out an important implementation detail: the path used in the Action directive must also be defined with ScriptAlias, otherwise Apache may treat the wrapper as static content instead of executing it.

An alternative Action based execution tip Mr Yowler:
Just a one-time contribution to your "Tips and Tricks" notes...

The tip descibed by Shane DeRidder works nicely, except that he left out one important detail:  whatever path you set up, as the "Action" for "cgi-wrapper", must be defined in a "ScriptAlias" directive, so that Apache knows to run the cgiwrap executable, 
rather than treat it as static content.  Here is a sample from my own setup; a VirtualHost on a webserver that lives in a chrooted environment:

<virtualhost>
  ServerAdmin 
  DocumentRoot /
  ServerName www.somedomain.com
  ErrorLog /path/to/logs/www.somedomain.com-error_log
  CustomLog /path/to/logs/www.somedomain.com-access_log
  ScriptAlias /cgi-bin/ /serverwide/script/path/
    <ifmodule mod_userdir.c>
    UserDir public_html
  </ifmodule>
    <directory home public_html>
   AllowOverride AuthConfig Limit
   Options Indexes Includes ExecCGI
   Action cgi-wrapper .cgi
  </directory>
</virtualhost>

This configuration allows users within the www.somedomain.com site, run .cgi scripts, from wherever they want, within their home directories.  It's is relatively transparent, as Shane DeRidder said, execpt for two things:

1) Any call for a script, that results in an error within CGIwrap (such as a call for a script that does not exist), results in an error, from the CGIwrap executable.  That error clearly labels itself as coming from CGIwrap, identifying to the user, that 
CGIwrappers are in place.

2) Any attempt to password-protect access to the scripts, using the .htaccess mechanism, will fail, since the CGIwrapper is outside of the users' writable file system tree.  Ordinarily, the user's would simply .htaccess-control the directory containing the script that they wrote.  With CGIwrap controlling script execution, however, Apache does not get an opportunity to check the .htaccess rules, for the script, and therefore, any script that the user intended to be password-protected or otherwise access-restricted, isn't.

I suspect that a careful application of suEXEC would resolve the latter issue, though the cost of doing so, would be the loss of some of the cooler resource-limiting functions of CGIwrap.

The symptom of failing to use ScriptAlias, on my system, was reflected in the Apache error log, as a "File does not exist" message pointing at the serverwide script path.

Anyhow, that's my little contribution.

Taken together, these tips show that CGIWrap can be deployed in a much more polished and flexible way than the basic documentation alone might suggest. The common themes are transparency, cleaner URLs, tighter control over debug access, and careful integration with existing server behavior so CGI execution stays secure without feeling awkward to end users.