| Home > Computersystemen > Software packages > WWW > CGI Scripts |
CGI Scripts on the Departmental Web server(s)
- All CGI scripts should start with :
-
This means that :
- You can use the CGI module for easy CGI programming; consult the perl documentation (with perldoc CGI) for more information.
- Only tainted perl scripts (-T flag), with warnings (-w flag), strict safe mode restrictions, verbose diagnostics and stack tracing (the use statements) enabled, are allowed.
- Each day, every cgi-bin script is checked to see whether it indeed starts with the above lines. The last 4 lines (about CGI) however are optional : you do not have to use the CGI module; but you really should consider using it, because it makes life so much easier, especially when using html forms.
- Because of the strict safe mode, you need to declare variables you want to use, with a my ( $variable1, $variable2 ) construct and to initialize them (with "" or 0).
- You can find some information about the tainted mode of perl and what to do about it, on : Summarized, the tainted mode of perl can be described as :
- Because of the tainted mode, you need to :
- set the PATH variable explicitely; the only directory containing commands is /bin unless you have commands in your private directoy as well. In that case, you might consider to add that directory as well, of course.
- use perl -Tc to check the (perl) syntax of a script, otherwise the -c check will complain about the -T option on the first line.
- check the (values of the) arguments/parameters of the script before you can use them. You can use /cw/wwwserver/extern/cgi-bin/wrapper as an example for how to do that.
- If you have a CGI script that is not such a tainted, restricted perl script and you do not want to or cannot change it (e.g. because it is a compiled executable and you do not have the source) you must create a wrapper script and call it from within that wrapper script.
- You can and should put the original script/executable in your private directory, but not in the public_html (sub-)directory; you do not want (the source code of) this script to be served by the web server and thus it should not reside in public_html.
- Because of the tainted mode, you need to check the (values of the) arguments/parameters of the script before you can call the original script with them. You can use /cw/wwwserver/extern/cgi-bin/wrapper as an example.
- put the original cgi-bin script in the cgi-bin (sub-)directory of your private directory (i.e. /cw/wwwserver/extern/users/<your login name>/cgi-bin)
- copy this wrapper script in one of the /cw/wwwserver/extern/cgi-bin/* directories and give it the same name as your original cgi-bin script.
- change this copy of the wrapper script, so that it calls the original cgi-bin script in your private directory :
- change the variable loginname to your own login name.
- you can also change the (sub-)directory your own cgi-bin scripts are located in, with the cgibindir variable.
- Errors, warnings and other irregularities can be found in the error log, so check there if you are testing/developing/using CGI scripts.
- Take special care about the pathnames you use within the script to refer to other files you need. Paths beginning with /cw/wwwserver/extern/ should work, others might not (e.g. refer to the private directory of a user as /cw/wwwserver/extern/users/<login>/).
-
CGI scripts are executed by the web server software using a special
account. This means that in order to be able to write information in
some file (e.g. in your private directory) that file must have its
permissions set to allow that account to write to it.
You can ask the programmeur van week to give the file you want to write to from within a CGI script, the group httpd and make it group-writable, or make that file owned by the user http but another group to which you belong as well and make it group writable. You cannot do this yourself because regular accounts are not member of that group and thus cannot change a file to that group, nor can they change the owner of a file. - You can (and should) test a CGI script from the command line before using it via the web server. In this way, you can weed out a lot of bugs, that would otherwise fill up the web server error log. Because the web server might be serving other pages at the same time as your script, it might also be difficult to find the error your script generated.
- If you want to have an E-Mail sent from within a CGI script, you can/must use the Mail::Sendmail module. Use perldoc Sendmail for more information. From the synopsis of that documentation :
#!/usr/local/bin/perl -Tw
# ensure all possible restrictions for safe programming are enabled
use strict;
# give more verbose warnings
use diagnostics;
# enable stack tracing for when things go wrong
use sigtrap;
# Tainted mode requires you to explicitely define the PATH variable
$ENV{PATH} = '/bin';
# an easy to use API to CGI programming, including forms
# use perldoc CGI for more information
use CGI;
These are the lines the /cw/wwwserver/extern/cgi-bin/wrapper example
script starts with, so you can compare with that.
Any variable that is set using data from outside the program (including data from the environment, from standard input, and from the command line) is considered tainted and cannot be used to affect anything else outside your program.
The taint can spread. If you use a tainted variable to set the value of another variable, the second variable also becomes tainted.
Tainted variables cannot be used in eval(), system(), exec() or piped open() calls. If you try to do so, Perl exits with a warning message.
The taint checks are there in order to force you to recognize when a variable is potentially dangerous.
The only way to untaint a tainted variable is by performing a pattern matching operation on it and extracting the matched substrings.
We do advise to check a CGI script in this way before putting it in the cgi-bin directories.
A typical example of `untainting' a variable is :
When checking the arguments, please be careful with what you allow to pass. The expression/check in this wrapper script should be safe; if you want to add characters to it, please reconsider if you really need them and please double check whether you do not allow too much.open(NUMBER,"$basedir/$datafile") || die "Could not open $basedir/$datafile : $!"; $num = <NUMBER>; $num =~ /(\d*)/; $num = $1; close(NUMBER);
A lot of attacks on web servers succeed because of CGI scripts that are easily abused by giving them unexpected input and thus making them do things that are not foreseen.
Especially white space characters like tab, new line, ..., and the shell characters like <, >, ;, | and & are dangerous to let pass and thus should never be allowed in the value for a CGI argument/parameter!
For cgi-bin scripts that use the GET method, you can even use this wrapper to check the arguments/parameters for you :
File uploads (with multipart/form-data) must always use the POST method, and thus cannot use this wrapper way of working.
You can use this wrapper script, however, as an example to guide you in changing your own script.
First check it using perl -Tc ... this checks the syntax and also finds some semantic errors and warnings.
A script using the GET method can be executed as it is, a script using the POST method expects some input via standard input. You can provide empty input using < /dev/null.
There are some environment variables with which you can even provide meaningfull arguments/parameters to both GET and POST scripts. Explaining them is outside the scope of this text however.
use Mail::Sendmail;
my %mail = ( To => 'you@there.com',
Subject => 'This is the subject',
Message => "This is a very short message"
);
if ( sendmail(%mail) ) {
print "OK. Log says:\n", $Mail::Sendmail::log;
}
else {
print "NOT OK. Error says:\n", $Mail::Sendmail::error;
}

