|
|
5. Examples
|
| |
These examples do represent a range of issues involved
in CGI programming using perl. I hope they are
useful in getting started.
They are in no sense
complete, and make no effort to deal with issues of
perl that do not relate somehow to CGI. Caveat Emptor
|
|
| | | |
| |
|
| |
|
|
|
Example 1 -- Trivial Case
|
| |
This script simply prints out 'hi'. Two things to note:
- The output of the script starts with:
Content-type: text/plain, followed by a blank line.
This is essential, so that the browser will know what mime type
is being returned. And without this, the browser will not
see the rest of your output, but will get an error message.
- The url. This url corresponds to a file on tigger,
whose full path is
/homes/home8/adabyron/cgi-bin/example1.pl
|
|
| |
|
|
|
Example 2 -- Authentication
|
| |
This script shows how to force the user to use bluestem authentication.
Important points:
- The authenticated netid appears in the
$ENV{REMOTE_USER}
- The url must start with https, and
you must use perlwrap-auth.
- If the user tries to circumvent authentication, then
$ENV{REMOTE_USER} will not contain a value.
The script can take appropriate action, either by issuing
an error message or by issuing a redirection.
- Using the variables
$ENV{SERVER_NAME} and
$ENV{SCRIPT_NAME} to reconstruct the url
is good programming. Every now and then, you may copy
a script or move it to a new location. This code is nicely portable.
|
|
| |
|
|
|
Example 3 -- Debugging I
|
| |
This script is broken on purpose. It left out the
Content-type directive, which is required
by HTTP.
- The error message when a user tries to run this script
is not particularly enlightening.
- Note the information you get in debug mode. In this particular
case, the script actually runs (i.e. there is no perl error),
it just puts out bad HTTP. You'll have to figure this out,
but debug mode sure helps. The clue is in the last line,
where there is no
Content-type
|
|
| |
|
|
|
Example 4 -- Debugging II
|
| |
Once more, we try a bad script to examine how to debug.
This time, we use a script with a perl error.
- Note, again, that the
server error message
is not very helpful to you or your users.
- When run in debug mode, both STDOUT and STDERR are
returned to your browser. In this case, you can get the
perl error and fix the problem. I'll leave it as an exercise
to the reader to fix this perl problem.
Sometimes you can fix perl errors just by running the script from
the command line, rather than through perlwrap. This doesn't
always work, because the web server environment is different
than the command line environment, and the script may behave
differently.
|
|
| |
|
|
|
Example 5 -- Dealing with input
|
| |
This example shows how to deal with user input, either from the
url, or from a form. In particular, this script has a dual
purpose -- if it receives good input (either from the url
or a form), it prints out what it received. But if it doesn't
receive input, it prints out a form that will submit values
back to the same script. I often like to code this way,
so that the input form and the input handling program reside
in the same file.
- I used CGI.pm to parse the input. This hides various
complications, and I highly recommend it. CGI.pm does
vastly more than this simple example, although I rarely
have need for too much more. You should check out
the details by logging onto tigger or icarus and typing
perldoc CGI.
- This particular invocation of CGI.pm doesn't care
if the input was from a GET request (i.e. in the url,
or sometimes from a form) or from a POST request (from a form).
- Note again the use of
$ENV{SCRIPT_NAME} to
make a self-referential url.
|
|
| |
|
|
|
Example 6 -- Taint Mode
|
| |
Here we start dealing with security concerns, so listen up!
This example runs the 'ls' command, to search the local
directory for files whose extension is supplied by the user.
Running a command through the shell is always a little
dangerous, because you have to be very sure you run the
command you want to run. This seems like a trivial statement
to beginners, but experts and hackers know how to take
advantage of naivete.
When the command is based on
user input, the danger increases significantly.
This is where taint mode comes in. It forces
you to examine user input, and to sanitize it,
before using it to influence anything outside your
program. In this case, you aren't trying to
influence anything outside your program,
but the call to ls does involve
the shell, and therefore could damage things,
so perl takes special care.
Here, the sanitizing is quite strong.
I use:
$extension =~ /^(\w{1,10})$/;
$extension = $1;
This means that the variable $extension can
only contain letters -- no spaces, no punctuation, no
oddball characters. And I know, from the use I intend
to put this to, that mere letters will not harm me.
In fact, I have been so cautious in this example, that
I will only accept between 1 and 10 letters. That's probably
overkill here, but it does indicate that I have thought
very carefully about the form of input I deem valid.
And that is key -- you must decide what is valid input.
If you accept any old input, what happens if I
construct a url like: ....example6.pl?ext=pl;rm%20%2Dr%20%2A
(Kids, don't try this at home. It could erase all your files.
Just remember, a hacker can try out any url he wants. He's
not limited to the links or forms you provide. Never assume
that input to a script comes from the form you provided!
- If you influence things outside your script (i.e deal with
files or invoke the shell), perl will force you to de-taint
any user input. Don't try to outwit perl -- give some thought
to what constitutes valid input, and do not accept any more
than you have to. Be extremely careful of accepting punctuation
or spaces. Of course, this advice depends strongly on exactly
how you use the input. Writing a user's input into a file
is much safer than using that input to determine a file name.
De-taint sensibly.
- Whenever you invoke an outside command (e.g.
ls
in this example), be sure to specify the full path (e.g.
/bin/ls). As a further precaution, set the
variables $ENV{PATH} and $ENV{ENV}
either to '' or to values that you know are safe.
Outside commands can be invoked in many ways, including
backticks, calls to fork(), system(), exec(), or open().
- Never assume a hacker has to use your links or forms.
A hacker can construct any input he wants, and can
send it to your script. Just because you use a select box
in a form doesn't mean a hacker can't put in his own options.
Program defensively.
|
|
| |
|
|
|
Example 7 -- Writing Files
|
| |
Writing files from a CGI script is no different than from
any other program. However, I have an example to illustrate
file locking. It's quite possible for a CGI script to be
invoked several times simultaneously, and for each of
these invocations to write to the same file. However,
if you are careful to lock and unlock the file properly,
this is not a major problem.
- Use the full path, for both commands and files.
- Check return codes. Don't assume that everything works all the time.
- Keep the output file locked as little as possible.
|
|
| |
|
|
|
Example 8 -- Writing DBM Files
|
| |
This is really the same example as before, but I use a DBM
file instead of an ascii file. If you don't know what
a DBM file is, and how to access them via perl's tie
function, just skip this example. The only reason to
include this example is that tie'd DBM files are a bit
trickier to lock than ascii files.
|
|
| |
|