The two biggest security holes are file i/o (reading from and writing to files) and sub-shells (where variables in the program can be interpreted as commands). The general way to avoid security holes is the same:
root)
@user_args=split(/&/,$ENV{'QUERY_STRING'});
foreach $file (@user_args) {
open(FILE,">$file");
print FILE "Hi there\n";
close(FILE);
}
read(STDIN,$buffer,$ENV{'CONTENT_LENGTH'});
@pairs=split(/&/,$buff);
foreach $pair (@pairs) {
($name,$value)=split(/=/,$pair);
$value=~tr/+/ /;
$value=~s/%([0-9A-Fa-f]{2})/pack("C",hex($1))/eg;
############# the next line is the important one ###############
$value=~tr/A-Za-z0-9//cd; #this wipes out anything non-alphanumeric
$form{$name}=$value;
}
## user-input in associative array %form
$form{'filename'}=~tr/~//d; #get rid of ~s
$form{'filename'}=~s/\.\.\///g; #get rid of ../s
open(HANDLE,"$startpath/$form{'filename'}");
{ } [ ] | ; < > & ( ) ! \
Any user-supplied information which will be sent to a sub-shell should
be run through something like this:
$form{'search'}=~tr/A-Za-z0-9 ._=+-//cd;
## $form{'search'} is now clean but can still contain the characters we specify
open(FIND,"grep $form{'search'} /export/home/me/mydatabase |");
You can also do something a little less invasive than that by escaping
those bad characters with a line like this:
$form{'search'}=~s/([{}[]|\;<>()])/\\$1/g;
This will put an escaping back-slash in front of any potentially
dangerous character.