Mythic Beasts

Safeperl

Safe Perl is a restricted CGI environment which allows us to give you CGI access cheaply without having to audit every script. Writing CGI for this environment can be a little more difficult than writing normal perl CGI since you must adhere to the rules of Safe Perl.

Safe Perl Scripting

Safe Perl creates a directory structure in your home directory under the /home/username/cgi directory. The following directories are created:

Safe Perl restricts many operations in perl but the most critical one from your point of view will probably be the open() call.

You can only open up files owned by you, using the open call. They will fail otherwise so remember to check that the open suceeded with something like:

open(HANDLE, "foo") or die "Cannot open foo!";

When you open files for writing they must exist in /home/username/cgi/out or be symlinks from that directory. Safe Perl runs as your user so you will not be able to overwrite any critical system files except the ones that affect your account. If you manage to cause havoc in your account do not expect too much sympathy.

You are not allowed to run programs within the CGI environment so backticks, system, and opening to pipes will not work. This is inconvenient for the commonly used pipe-to-sendmail method of mailing and so Safe Perl provides a mail function which can be used like this:

mail("huggie\@earth.li", "This is a subject",

"Hi,\nThis is a really interesting email sent from safeperl\n\n -- \nThe Safe Perl Automailer.");

Remember to escape the @ in the address. If you don't perl will tell you to.

Safe Perl also provides a limited mechanism for getting at the data sent to your script through the GET or POST methods. Calling raw_query will result in the QUERY_STRING or STDIN being read and returned to you based on the contents of REQUEST_METHOD. parsed_query splits the raw_query at & and = characters resulting in an array consisting of key, value. It is however impossible to tell from this whether you have been passed two blank keys or a key and value pair.
We recommend you do your own parsing

Something like this should work:

my $meth = $ENV{REQUEST_METHOD};
if ($meth eq "GET") {
$query = $ENV{QUERY_STRING};
} elsif ($meth eq "POST") {
read(STDIN, $query, $ENV{CONTENT_LENGTH});
} else {
die("Bad request method. Request method must be GET or POST");
}

@pairs = split(/&/, $query);
foreach $pair (@pairs) {
($name, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$value =~ s/\0//g;
$name  =~ s/\0//g;
$FORM{$name} = $value;
}

NB, this code is licensed under the GPL and thus comes with no warranty.

As with all security sensitive applications you should probably check for what you want to allow rather than attempting to deny what you don't want.

Here is the list of restricted operations from Safe Perl's README:

There are many Perl operators not available to the compartment in which your CGI program is run. These mostly include operators which provide access to the operating system. The following list is not exhaustive but includes the most common excluded operators:

  • system, `backticks`, exec, fork, syscall, signal handlers, pipes (including open(FOO, "|bar") and open(FOO, "bar|"))
  • network access (socket, bind, connect, ...)
  • File munging (rename, link, opendir, chown, ...)
  • System V IPC (shared memory, message queues, semaphores)
  • File tests (-r, -w, -l, ...)
  • Calling perl on other files (require, use, do 'file')

Opening files for reading/writing is restricted. The "open" command is subject to the following restrictions:

  • Files opened for reading must be owned by the user.
  • Files opened for writing must be opened by using a filename containing no "/" characters. The filename is taken to live in the directory ~/cgi/out and the file must already exist at the time the open is performed. It can be a symbolic link if desired.

Attempting to use any of the above functions will result in a runtime error.
Safe Perl will not honour any #! lines in your program.

Finally, the URL you should use to access your Safe Perl scripts is:
http://www.yourdomainname.co.uk/cgi-bin/safeperl/scriptname

NB Please note that on running your script, assumptions about $_ and @_ should not be made. Specifically calling a function and expecting @_ to be empty will fail.

Safe Perl with a database

We can provide you with a PostgreSQL database to use with SafePerl - please contact us for a quote if you require this.

You should put the password for your database in /home/<username>/cgi/dbpass; SafePerl will then pick this up and automatically connect to it for you. A DBI handle will then be available as $dbh in your code.

Copyright © 2000-2008 Mythic Beasts Ltd. All Rights Reserved.