|
Writing Secure Perl Programs
Peter HaworthIOP Publishing Ltd.
O'Reilly Open Source Convention July 22-26, 2002
|
Outline
|
Introduction
Don't trust the user
|
Robustnessopen STDOUT,'> write-protected';
if( $x == 1 ){
do_this();
}elsif( $x == 2 ){
do_that();
}
perl -T
|
Tainting$^X @ARGV %ENV <> read() readline() `` qx() etc shmread() msgrcv() getpw*() etc `` qx() system() exec() kill() unlink() mkdir() umask() chmod() etc open() (for writing) NOT print() or write() $1, $2, etc are (almost) never taintedmy($untainted) = $tainted =~ /(\d+)/;
|
Child processes%ENV=( PATH => '/bin:/usr/bin' ); %ENV taint checksPATH IFS CDPATH ENV BASH_ENV # Unsafe: $file eq "; rm -rf /" system "prog $file" and die; # Safe system "prog \Q$file\E" and die; # No shell, and less taint checks (for now) system '/bin/prog',$file and die;
|
Child processes - Safe pipesopen my $fh,"| mail $user" or die; print $fh $msg; close $fh or die; open my $fh,"| /bin/mail \Q$user\E" or die; print $fh $msg; close $fh or die;
defined(my $pid=open my $fh,'|-') or die;
if(!$pid){
exec '/bin/mail',$user;
die "Can't exec";
}
print $fh $msg;
close $fh or die;
open my $fh,'|-','/bin/mail',$user or die; print $fh $msg; close $fh or die;
|
Validate all user inputdie "Bad!" if /[;<>&^"']/; # Bad! die "Bad!" unless /\A[\w\s]+\z/; # Good
my ($num) = $input =~ /\A(\d+)\z/
or die "Not an integer";
$num >= 0 && $num <= 100
or die "Out of range";
|
Filenames
# Unsafe if $filename eq "/etc/passwd\0"
open my $fh, '<', "$filename.safe"
or die "Invalid filename";
# Safer
die "Invalid filename"
if $filename =~ /\0/;
open my $fh, '<', "$filename.safe"
or die "Invalid filename";
# Prevents ../../../../etc/passwd
die "Invalid filename"
if $filename =~ m#/#;
die "Invalid filename"
unless $filename =~ /\A\w+\z/;
|
Magic
|
Web applications - HTML forms
<input type="hidden" name="password"
value="secret">
# Unsafe
# fname=stuff&fname=action&fname=delete
%config = (
action => 'create',
filename => $cgi->param('fname'),
);
# Safe
$sth->execute(
scalar $cgi->param('fname')
);
|
Web applications - Cookies# Standard with perl 5.8.0 use Digest::MD5 qw(md5_hex);
$cookie_val = $val . md5_hex(
md5_hex($val . $secret1) . $secret2
);
|
Safe sequence numbers
|
Dynamic method names
|
References
|