Home Articles FAQs XREF Games Software Instant Books BBS About FOLDOC RFCs Feedback Sitemap
irt.Org

Related items

Creating a Page Counter In Perl

Speed Thrills : CGI Please ... and Fast!

CGI Programming Made (Relatively) Easy Using Libraries

Server-Side Includes and its Extensions

Random and Recursive Crypting using Salt on Unix and Win32

Timestamping an HTML Document

Deleting Files in Perl

Creating a mailing list using Perl

Reading and Writing to Files on the Server

CGI - Server Side Processing of Form Data

Server Side Includes and CGI Security

You are here: irt.org | Articles | CGI & Perl | Server Side Includes and CGI Security [ previous next ]

Published on: Saturday 4th July 1998 By: Jason Nugent

Introduction

This CGI article is going to focus on a few things that tend to crop up in the same sentence - Server Side Includes, and CGI security. I will deal with both separately, though, since I feel that they both deserve an independent discussion.

Server Side Includes

In the past few articles, we have seen how to pass information from a HTML form to a CGI script sitting on a server. We have seen how to parse this information and extract it into a useable form and then display this information back to the visitor. In short, we've accomplished quite a bit. What if, though, we wanted to include the results of a CGI script in an HTML document, but not actually generate the whole thing from the script? What if we wanted to include the same section of HTML at the bottom of each page in our site, but not have to continually re-enter this code on every page? What if we wanted to have the modification date and time at the bottom of our site, so that it gets updated by itself each time we make a change to the file?

It sounds pretty good, doesn't it? In fact, these things are quite simple to do, and most of them require little if any knowledge of a CGI scripting language.

Different types of Includes

There are several different types of includes, and each one does something different. Without further ado, the different types are

The two that are used most often are exec and include. In a lot of cases, the exec server side include is not enabled on the server because it can potentially open many security holes. Before we get into how each one works, lets take a look at the syntax of the general include command.

The HTML Syntax of the Command

<!--#command tag="argument" -->

You will notice that it bears a striking semblance to the HTML comment tag. The syntax of the SSI tag is very strict - there must not be a space between <!-- and #command, and the # symbol must be present. If this syntax is not followed, your tag will not be interpreted as a server side include and will most likely be rendered as a regular comment.

The include Command

The include tag is a very useful tag. It allows a section of code to be inserted in place of it, and the code that is inserted may be stored in an external file. This file must be relative to the directory you are serving your HTML document from - it will not work if you specify an absolute path (which will be interpreted relative to SERVER_ROOT) It takes the following syntax:

<!--#include file="text.html" -->

Where file="text.html" specifies that you want to include the file "text.html" in place of the server side include. If you wish to include a file that is relative to the SERVER_ROOT, you may use the virtual="/file.html" syntax instead of file="file.html". The server will prepend the SERVER_ROOT to the front of the path and serve the file in place of the include.

The fsize Command

The fsize command is very similar to the include command. It inserts the file size of the specified file in place of the include. It takes the following syntax:

<!--#fsize file="text.html" -->

It also must be relative to the directory that the file containing the SSI is in. A filename beginning with a slash (/) will cause an error. There is no virtual parameter for the fsize command.

The flastmod Command

The flastmod include also takes a file="filename" argument and returns the modification date of the file specified. Again, there is no "virtual" parameter for the flastmod command. It has the following syntax:

<!--#flastmod file="index.html" -->

This will insert the modification date of index.html into the document containing the flastmod SSI.

The echo Command

The echo include allows you to insert environment variables into your otherwise static HTML document. All environmental variables otherwise available to CGI applications are available to the echo include. The echo include has the following syntax:

<!--#echo var="argument" -->

where argument is the name of a variable, including LAST_MODIFIED, DOCUMENT_NAME, DOCUMENT_URI, DATE_LOCAL, and SERVER_NAME. There are others as well.

The config Command

The config include gives you the ability to tailor the output of other SSIs on the page. With it, date formats from flastmod, or the size outputted from fsize can be customized. Error messages can be customized as well. It takes the following syntax:

<!--#config errmsg="New Error Message Goes Here" -->

or also

<!--#config sizefmt="abbrev" -->

which will abbreviate file sizes outputted from the fsize command so they are displayed in kilobytes (rather than bytes, which is the default). If errmsg is set, this message will be displayed in place of the standard error for SSIs, which is

[an error occurred while processing this directive]

which isn't very helpful.

The exec Command

I have saved this one for last, since it is probably the most powerful but also the most dangerous. With it, the output of a CGI script may be included where the SSI is in the HTML page. The CGI script may do just about anything - it could be a counter, perhaps, which updates your counter file and displays the number of visitors on the page. It takes two different parameters, cmd and cgi. The format is the same as the other includes:

<!--#exec cgi="/cgi-bin/script.pl" -->

or

<!--#exec cmd="/bin/ls -l /home/www/htdocs" -->

The first parameter (cgi) takes a CGI script as a parameter. There are a few restrictions, however, on the type of output it can display. Only a text/plain or text/html content type may be returned. The reason for this is because the output of the CGI script must be taken in the context of the HTML page that called it. It would be of little use, for example, to return a content type of application/msword, since the browser would have no idea what to do with it. Also, you may not pass a QUERY_STRING to the CGI script via a SSI. For example, the following include will generate an error:

<!--#exec cgi="/cgi-bin/script.pl?hello" -->

The second parameter (cmd) takes any command that may run on the server. In the example above, however, the long format listing of /home/www/htdocs will be inserted into the HTML document.

Server Setup for Server Side Includes

In order to get SSI's working, your server needs to be set up for them. In particular, since the server must "know" that there are includes present in your HTML document, there are several changes that have to be implemented before they will work.

For Apache (the most popular web server on the Internet today), two changes must be made. In the srm.conf file (the Server Resource Management file), a new type must be added that tells Apache to parse through files that have a special file extension:

AddHandler server-parsed .shtml .sht .shtm

This line will instruct the server to parse files that end in .shtml, .shtm and .sht. You must also make a change to the access.conf file (the file that tells Apache what is allowed on the server, and by whom). This change involves setting the Options directive for the server you want to add SSIs to:

Options IncludesNOEXEC 

This will instruct Apache to allow Includes, and also NOT let you use the "exec" include. Note that exec isn't automatically grouped in with the other includes. Because there are security problems associated with it, it must be explicitly turned on. If you wish to use all includes, replace "IncludesNOEXEC" with "Includes".

I should point out that the most recent distribution of Apache has these items ready to go in the configuration files - all you have to do is uncomment a few lines and you should be ready to roll.

Security and CGI - Read this Twice

I've been talking a lot lately about CGI, and hinting at certain things that may open security holes on a server (like the exec server side include). I'm going to say a few things now that will hopefully get you thinking about security when you write your future scripts.

First and foremost, make sure you examine any information submitted from a FORM to your CGI script. If you, for whatever reason, use information as arguments to a command that is getting executed on the server, make sure you check it for content first. For example - let's say you are providing a method for fingering a user on a different server and you provide a text box on a form in which a visitor can enter a username to finger. What if they typed this:

me@where.com ; /bin/rm -rf *

Well, if this gets passed to a finger command (provided the finger command was called using backticks or the system command, you end up with this:

finger me@where.com ; /bin/rm -rf *

Which will do TWO things - it will finger the user me@where.com, and then it will execute /bin/rm -rf * which will try to remove every single file on your server. It probably won't get them all since the command will run as the user that the web server runs as (usually user "nobody"), but it will delete more than you would like it to. I guarantee it.

You may want to also add another flag to perl's interpreter line - -T. The -T flag turns on data tainting which forces the script consider all external variables (command line arguments, Environmental variables, and variables containing file input, for example) as "bad" until told otherwise. For example:

#!/usr/local/bin/perl -Tw
$path = $ENV{'PATH'};

Would be considered tainted data. To "untaint" it, you would have to explicitly set the $path variable from inside the program:

$ENV{'PATH'} = '/bin:/sbin/:/usr/bin';
$path = $ENV{'PATH'};  # data no longer tainted

Note that this example is a bit simplistic - I'm not really doing anything other than clobbering the data stored in the path environmental variable with something from the inside. In almost every useful case, you will have to check your data quite thoroughly to ensure that there is nothing wrong with it.

If you write a script that isn't going to be posted on the Internet somewhere, "free for download", hardcode any values that will never change. The less you give a cracker to play with, the better. Anything that your script doesn't have to read in from a GET or POST is one more plus on your side.

If tainting is turned on, Perl will give you a warning if you try to do something explicitly insecure, and will die with a "Insecure dependancy" warning if you do.

Another good practice is making sure that CGI scripts aren't being run separately (when they should be run by forms or as an exec server side include). Scripts being run by themselves could be a sign that someone is either trying to steal your resources or feed it information in order to see "what it does". A good way to prevent this is to make sure that the HTTP_REFERER environmental variable is set to either the server name that your pages are on (if you want to use the same CGI script on several pages), or to a server name and page (like www.irt.org/index.html) if you want to make sure it will only be run from a single page.

Something to remember here, though - the HTTP_REFERER variable isn't always set, and can sometimes even be forged. Don't rely on it for all your security needs. You still have to check the input of form tags or anything else submitted to the server for malicious code. It just pays to be smart about stuff like this.

I'm actually going to stand here for a second and tell you that there are strong reasons why you shouldn't use this variable. Opera, a browser that is becoming increasingly more popular, does NOT set it during requests and in fact, there is an RFC that is currently mandating that HTTP_REFERER be optional when performing a request for a document. You just can't count on it.

Bear in mind that you should always use redundant security precautions to make sure that your scripts are running securely. Without exception, any serious CGI programs that I write always include variable checking and input parsing to make sure that my server won't be damaged.

Lastly, remember that security doesn't only protect you from malicious users. It is just as easy for an accident to happen. A visitor might accidentally enter dangerous metacharacters in your form field and submit the form without checking. Being prepared for all types of situations will help you sleep easier at night.

There are several good sources for information on CGI security. If you want to be on top of your stuff, examine these resources:

The first resource has a ton of links (both internal and external) to other good resources. The second one is the site of the CERT Coordination Center, an organization that studies Internet security vulerabilities. You may subscribe to a mailing list to be notified when a new hole is discovered.

The Next Issue

The next issue will deal with handling files on the server in order to store information for an extended period of time. One of the best things about CGI is that you can use it to maintain information about your visitors and later retrieve this information so that you might perform some useful task with it (store it in a database, for instance). The next issue will show you how to read and write files on a server. Perl techniques to do this will include open(), close(), and flock(). Previous commands will also be expanded on.

Related items

Creating a Page Counter In Perl

Speed Thrills : CGI Please ... and Fast!

CGI Programming Made (Relatively) Easy Using Libraries

Server-Side Includes and its Extensions

Random and Recursive Crypting using Salt on Unix and Win32

Timestamping an HTML Document

Deleting Files in Perl

Creating a mailing list using Perl

Reading and Writing to Files on the Server

CGI - Server Side Processing of Form Data

©2018 Martin Webb