625 lines
28 KiB
Plaintext
625 lines
28 KiB
Plaintext
=head1 NAME
|
|
|
|
perlsec - Perl security
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
Perl is designed to make it easy to program securely even when running
|
|
with extra privileges, like setuid or setgid programs. Unlike most
|
|
command line shells, which are based on multiple substitution passes on
|
|
each line of the script, Perl uses a more conventional evaluation scheme
|
|
with fewer hidden snags. Additionally, because the language has more
|
|
builtin functionality, it can rely less upon external (and possibly
|
|
untrustworthy) programs to accomplish its purposes.
|
|
|
|
=head1 SECURITY VULNERABILITY CONTACT INFORMATION
|
|
|
|
If you believe you have found a security vulnerability in Perl, please
|
|
email the details to perl5-security-report@perl.org. This creates a new
|
|
Request Tracker ticket in a special queue which isn't initially publicly
|
|
accessible. The email will also be copied to a closed subscription
|
|
unarchived mailing list which includes all the core committers, who will
|
|
be able to help assess the impact of issues, figure out a resolution, and
|
|
help co-ordinate the release of patches to mitigate or fix the problem
|
|
across all platforms on which Perl is supported. Please only use this
|
|
address for security issues in the Perl core, not for modules
|
|
independently distributed on CPAN.
|
|
|
|
When sending an initial request to the security email address, please
|
|
don't Cc any other parties, because if they reply to all, the reply will
|
|
generate yet another new ticket. Once you have received an initial reply
|
|
with a C<[perl #NNNNNN]> ticket number in the headline, it's okay to Cc
|
|
subsequent replies to third parties: all emails to the
|
|
perl5-security-report address with the ticket number in the subject line
|
|
will be added to the ticket; without it, a new ticket will be created.
|
|
|
|
=head1 SECURITY MECHANISMS AND CONCERNS
|
|
|
|
=head2 Taint mode
|
|
|
|
Perl automatically enables a set of special security checks, called I<taint
|
|
mode>, when it detects its program running with differing real and effective
|
|
user or group IDs. The setuid bit in Unix permissions is mode 04000, the
|
|
setgid bit mode 02000; either or both may be set. You can also enable taint
|
|
mode explicitly by using the B<-T> command line flag. This flag is
|
|
I<strongly> suggested for server programs and any program run on behalf of
|
|
someone else, such as a CGI script. Once taint mode is on, it's on for
|
|
the remainder of your script.
|
|
|
|
While in this mode, Perl takes special precautions called I<taint
|
|
checks> to prevent both obvious and subtle traps. Some of these checks
|
|
are reasonably simple, such as verifying that path directories aren't
|
|
writable by others; careful programmers have always used checks like
|
|
these. Other checks, however, are best supported by the language itself,
|
|
and it is these checks especially that contribute to making a set-id Perl
|
|
program more secure than the corresponding C program.
|
|
|
|
You may not use data derived from outside your program to affect
|
|
something else outside your program--at least, not by accident. All
|
|
command line arguments, environment variables, locale information (see
|
|
L<perllocale>), results of certain system calls (C<readdir()>,
|
|
C<readlink()>, the variable of C<shmread()>, the messages returned by
|
|
C<msgrcv()>, the password, gcos and shell fields returned by the
|
|
C<getpwxxx()> calls), and all file input are marked as "tainted".
|
|
Tainted data may not be used directly or indirectly in any command
|
|
that invokes a sub-shell, nor in any command that modifies files,
|
|
directories, or processes, B<with the following exceptions>:
|
|
|
|
=over 4
|
|
|
|
=item *
|
|
|
|
Arguments to C<print> and C<syswrite> are B<not> checked for taintedness.
|
|
|
|
=item *
|
|
|
|
Symbolic methods
|
|
|
|
$obj->$method(@args);
|
|
|
|
and symbolic sub references
|
|
|
|
&{$foo}(@args);
|
|
$foo->(@args);
|
|
|
|
are not checked for taintedness. This requires extra carefulness
|
|
unless you want external data to affect your control flow. Unless
|
|
you carefully limit what these symbolic values are, people are able
|
|
to call functions B<outside> your Perl code, such as POSIX::system,
|
|
in which case they are able to run arbitrary external code.
|
|
|
|
=item *
|
|
|
|
Hash keys are B<never> tainted.
|
|
|
|
=back
|
|
|
|
For efficiency reasons, Perl takes a conservative view of
|
|
whether data is tainted. If an expression contains tainted data,
|
|
any subexpression may be considered tainted, even if the value
|
|
of the subexpression is not itself affected by the tainted data.
|
|
|
|
Because taintedness is associated with each scalar value, some
|
|
elements of an array or hash can be tainted and others not.
|
|
The keys of a hash are B<never> tainted.
|
|
|
|
For example:
|
|
|
|
$arg = shift; # $arg is tainted
|
|
$hid = $arg . 'bar'; # $hid is also tainted
|
|
$line = <>; # Tainted
|
|
$line = <STDIN>; # Also tainted
|
|
open FOO, "/home/me/bar" or die $!;
|
|
$line = <FOO>; # Still tainted
|
|
$path = $ENV{'PATH'}; # Tainted, but see below
|
|
$data = 'abc'; # Not tainted
|
|
|
|
system "echo $arg"; # Insecure
|
|
system "/bin/echo", $arg; # Considered insecure
|
|
# (Perl doesn't know about /bin/echo)
|
|
system "echo $hid"; # Insecure
|
|
system "echo $data"; # Insecure until PATH set
|
|
|
|
$path = $ENV{'PATH'}; # $path now tainted
|
|
|
|
$ENV{'PATH'} = '/bin:/usr/bin';
|
|
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
|
|
|
|
$path = $ENV{'PATH'}; # $path now NOT tainted
|
|
system "echo $data"; # Is secure now!
|
|
|
|
open(FOO, "< $arg"); # OK - read-only file
|
|
open(FOO, "> $arg"); # Not OK - trying to write
|
|
|
|
open(FOO,"echo $arg|"); # Not OK
|
|
open(FOO,"-|")
|
|
or exec 'echo', $arg; # Also not OK
|
|
|
|
$shout = `echo $arg`; # Insecure, $shout now tainted
|
|
|
|
unlink $data, $arg; # Insecure
|
|
umask $arg; # Insecure
|
|
|
|
exec "echo $arg"; # Insecure
|
|
exec "echo", $arg; # Insecure
|
|
exec "sh", '-c', $arg; # Very insecure!
|
|
|
|
@files = <*.c>; # insecure (uses readdir() or similar)
|
|
@files = glob('*.c'); # insecure (uses readdir() or similar)
|
|
|
|
# In either case, the results of glob are tainted, since the list of
|
|
# filenames comes from outside of the program.
|
|
|
|
$bad = ($arg, 23); # $bad will be tainted
|
|
$arg, `true`; # Insecure (although it isn't really)
|
|
|
|
If you try to do something insecure, you will get a fatal error saying
|
|
something like "Insecure dependency" or "Insecure $ENV{PATH}".
|
|
|
|
The exception to the principle of "one tainted value taints the whole
|
|
expression" is with the ternary conditional operator C<?:>. Since code
|
|
with a ternary conditional
|
|
|
|
$result = $tainted_value ? "Untainted" : "Also untainted";
|
|
|
|
is effectively
|
|
|
|
if ( $tainted_value ) {
|
|
$result = "Untainted";
|
|
} else {
|
|
$result = "Also untainted";
|
|
}
|
|
|
|
it doesn't make sense for C<$result> to be tainted.
|
|
|
|
=head2 Laundering and Detecting Tainted Data
|
|
|
|
To test whether a variable contains tainted data, and whose use would
|
|
thus trigger an "Insecure dependency" message, you can use the
|
|
C<tainted()> function of the Scalar::Util module, available in your
|
|
nearby CPAN mirror, and included in Perl starting from the release 5.8.0.
|
|
Or you may be able to use the following C<is_tainted()> function.
|
|
|
|
sub is_tainted {
|
|
local $@; # Don't pollute caller's value.
|
|
return ! eval { eval("#" . substr(join("", @_), 0, 0)); 1 };
|
|
}
|
|
|
|
This function makes use of the fact that the presence of tainted data
|
|
anywhere within an expression renders the entire expression tainted. It
|
|
would be inefficient for every operator to test every argument for
|
|
taintedness. Instead, the slightly more efficient and conservative
|
|
approach is used that if any tainted value has been accessed within the
|
|
same expression, the whole expression is considered tainted.
|
|
|
|
But testing for taintedness gets you only so far. Sometimes you have just
|
|
to clear your data's taintedness. Values may be untainted by using them
|
|
as keys in a hash; otherwise the only way to bypass the tainting
|
|
mechanism is by referencing subpatterns from a regular expression match.
|
|
Perl presumes that if you reference a substring using $1, $2, etc. in a
|
|
non-tainting pattern, that
|
|
you knew what you were doing when you wrote that pattern. That means using
|
|
a bit of thought--don't just blindly untaint anything, or you defeat the
|
|
entire mechanism. It's better to verify that the variable has only good
|
|
characters (for certain values of "good") rather than checking whether it
|
|
has any bad characters. That's because it's far too easy to miss bad
|
|
characters that you never thought of.
|
|
|
|
Here's a test to make sure that the data contains nothing but "word"
|
|
characters (alphabetics, numerics, and underscores), a hyphen, an at sign,
|
|
or a dot.
|
|
|
|
if ($data =~ /^([-\@\w.]+)$/) {
|
|
$data = $1; # $data now untainted
|
|
} else {
|
|
die "Bad data in '$data'"; # log this somewhere
|
|
}
|
|
|
|
This is fairly secure because C</\w+/> doesn't normally match shell
|
|
metacharacters, nor are dot, dash, or at going to mean something special
|
|
to the shell. Use of C</.+/> would have been insecure in theory because
|
|
it lets everything through, but Perl doesn't check for that. The lesson
|
|
is that when untainting, you must be exceedingly careful with your patterns.
|
|
Laundering data using regular expression is the I<only> mechanism for
|
|
untainting dirty data, unless you use the strategy detailed below to fork
|
|
a child of lesser privilege.
|
|
|
|
The example does not untaint C<$data> if C<use locale> is in effect,
|
|
because the characters matched by C<\w> are determined by the locale.
|
|
Perl considers that locale definitions are untrustworthy because they
|
|
contain data from outside the program. If you are writing a
|
|
locale-aware program, and want to launder data with a regular expression
|
|
containing C<\w>, put C<no locale> ahead of the expression in the same
|
|
block. See L<perllocale/SECURITY> for further discussion and examples.
|
|
|
|
=head2 Switches On the "#!" Line
|
|
|
|
When you make a script executable, in order to make it usable as a
|
|
command, the system will pass switches to perl from the script's #!
|
|
line. Perl checks that any command line switches given to a setuid
|
|
(or setgid) script actually match the ones set on the #! line. Some
|
|
Unix and Unix-like environments impose a one-switch limit on the #!
|
|
line, so you may need to use something like C<-wU> instead of C<-w -U>
|
|
under such systems. (This issue should arise only in Unix or
|
|
Unix-like environments that support #! and setuid or setgid scripts.)
|
|
|
|
=head2 Taint mode and @INC
|
|
|
|
When the taint mode (C<-T>) is in effect, the "." directory is removed
|
|
from C<@INC>, and the environment variables C<PERL5LIB> and C<PERLLIB>
|
|
are ignored by Perl. You can still adjust C<@INC> from outside the
|
|
program by using the C<-I> command line option as explained in
|
|
L<perlrun>. The two environment variables are ignored because
|
|
they are obscured, and a user running a program could be unaware that
|
|
they are set, whereas the C<-I> option is clearly visible and
|
|
therefore permitted.
|
|
|
|
Another way to modify C<@INC> without modifying the program, is to use
|
|
the C<lib> pragma, e.g.:
|
|
|
|
perl -Mlib=/foo program
|
|
|
|
The benefit of using C<-Mlib=/foo> over C<-I/foo>, is that the former
|
|
will automagically remove any duplicated directories, while the latter
|
|
will not.
|
|
|
|
Note that if a tainted string is added to C<@INC>, the following
|
|
problem will be reported:
|
|
|
|
Insecure dependency in require while running with -T switch
|
|
|
|
=head2 Cleaning Up Your Path
|
|
|
|
For "Insecure C<$ENV{PATH}>" messages, you need to set C<$ENV{'PATH'}> to
|
|
a known value, and each directory in the path must be absolute and
|
|
non-writable by others than its owner and group. You may be surprised to
|
|
get this message even if the pathname to your executable is fully
|
|
qualified. This is I<not> generated because you didn't supply a full path
|
|
to the program; instead, it's generated because you never set your PATH
|
|
environment variable, or you didn't set it to something that was safe.
|
|
Because Perl can't guarantee that the executable in question isn't itself
|
|
going to turn around and execute some other program that is dependent on
|
|
your PATH, it makes sure you set the PATH.
|
|
|
|
The PATH isn't the only environment variable which can cause problems.
|
|
Because some shells may use the variables IFS, CDPATH, ENV, and
|
|
BASH_ENV, Perl checks that those are either empty or untainted when
|
|
starting subprocesses. You may wish to add something like this to your
|
|
setid and taint-checking scripts.
|
|
|
|
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; # Make %ENV safer
|
|
|
|
It's also possible to get into trouble with other operations that don't
|
|
care whether they use tainted values. Make judicious use of the file
|
|
tests in dealing with any user-supplied filenames. When possible, do
|
|
opens and such B<after> properly dropping any special user (or group!)
|
|
privileges. Perl doesn't prevent you from
|
|
opening tainted filenames for reading,
|
|
so be careful what you print out. The tainting mechanism is intended to
|
|
prevent stupid mistakes, not to remove the need for thought.
|
|
|
|
Perl does not call the shell to expand wild cards when you pass C<system>
|
|
and C<exec> explicit parameter lists instead of strings with possible shell
|
|
wildcards in them. Unfortunately, the C<open>, C<glob>, and
|
|
backtick functions provide no such alternate calling convention, so more
|
|
subterfuge will be required.
|
|
|
|
Perl provides a reasonably safe way to open a file or pipe from a setuid
|
|
or setgid program: just create a child process with reduced privilege who
|
|
does the dirty work for you. First, fork a child using the special
|
|
C<open> syntax that connects the parent and child by a pipe. Now the
|
|
child resets its ID set and any other per-process attributes, like
|
|
environment variables, umasks, current working directories, back to the
|
|
originals or known safe values. Then the child process, which no longer
|
|
has any special permissions, does the C<open> or other system call.
|
|
Finally, the child passes the data it managed to access back to the
|
|
parent. Because the file or pipe was opened in the child while running
|
|
under less privilege than the parent, it's not apt to be tricked into
|
|
doing something it shouldn't.
|
|
|
|
Here's a way to do backticks reasonably safely. Notice how the C<exec> is
|
|
not called with a string that the shell could expand. This is by far the
|
|
best way to call something that might be subjected to shell escapes: just
|
|
never call the shell at all.
|
|
|
|
use English;
|
|
die "Can't fork: $!" unless defined($pid = open(KID, "-|"));
|
|
if ($pid) { # parent
|
|
while (<KID>) {
|
|
# do something
|
|
}
|
|
close KID;
|
|
} else {
|
|
my @temp = ($EUID, $EGID);
|
|
my $orig_uid = $UID;
|
|
my $orig_gid = $GID;
|
|
$EUID = $UID;
|
|
$EGID = $GID;
|
|
# Drop privileges
|
|
$UID = $orig_uid;
|
|
$GID = $orig_gid;
|
|
# Make sure privs are really gone
|
|
($EUID, $EGID) = @temp;
|
|
die "Can't drop privileges"
|
|
unless $UID == $EUID && $GID eq $EGID;
|
|
$ENV{PATH} = "/bin:/usr/bin"; # Minimal PATH.
|
|
# Consider sanitizing the environment even more.
|
|
exec 'myprog', 'arg1', 'arg2'
|
|
or die "can't exec myprog: $!";
|
|
}
|
|
|
|
A similar strategy would work for wildcard expansion via C<glob>, although
|
|
you can use C<readdir> instead.
|
|
|
|
Taint checking is most useful when although you trust yourself not to have
|
|
written a program to give away the farm, you don't necessarily trust those
|
|
who end up using it not to try to trick it into doing something bad. This
|
|
is the kind of security checking that's useful for set-id programs and
|
|
programs launched on someone else's behalf, like CGI programs.
|
|
|
|
This is quite different, however, from not even trusting the writer of the
|
|
code not to try to do something evil. That's the kind of trust needed
|
|
when someone hands you a program you've never seen before and says, "Here,
|
|
run this." For that kind of safety, you might want to check out the Safe
|
|
module, included standard in the Perl distribution. This module allows the
|
|
programmer to set up special compartments in which all system operations
|
|
are trapped and namespace access is carefully controlled. Safe should
|
|
not be considered bullet-proof, though: it will not prevent the foreign
|
|
code to set up infinite loops, allocate gigabytes of memory, or even
|
|
abusing perl bugs to make the host interpreter crash or behave in
|
|
unpredictable ways. In any case it's better avoided completely if you're
|
|
really concerned about security.
|
|
|
|
=head2 Shebang Race Condition
|
|
|
|
Beyond the obvious problems that stem from giving special privileges to
|
|
systems as flexible as scripts, on many versions of Unix, set-id scripts
|
|
are inherently insecure right from the start. The problem is a race
|
|
condition in the kernel. Between the time the kernel opens the file to
|
|
see which interpreter to run and when the (now-set-id) interpreter turns
|
|
around and reopens the file to interpret it, the file in question may have
|
|
changed, especially if you have symbolic links on your system.
|
|
|
|
Some Unixes, especially more recent ones, are free of this
|
|
inherent security bug. On such systems, when the kernel passes the name
|
|
of the set-id script to open to the interpreter, rather than using a
|
|
pathname subject to meddling, it instead passes I</dev/fd/3>. This is a
|
|
special file already opened on the script, so that there can be no race
|
|
condition for evil scripts to exploit. On these systems, Perl should be
|
|
compiled with C<-DSETUID_SCRIPTS_ARE_SECURE_NOW>. The F<Configure>
|
|
program that builds Perl tries to figure this out for itself, so you
|
|
should never have to specify this yourself. Most modern releases of
|
|
SysVr4 and BSD 4.4 use this approach to avoid the kernel race condition.
|
|
|
|
If you don't have the safe version of set-id scripts, all is not lost.
|
|
Sometimes this kernel "feature" can be disabled, so that the kernel
|
|
either doesn't run set-id scripts with the set-id or doesn't run them
|
|
at all. Either way avoids the exploitability of the race condition,
|
|
but doesn't help in actually running scripts set-id.
|
|
|
|
If the kernel set-id script feature isn't disabled, then any set-id
|
|
script provides an exploitable vulnerability. Perl can't avoid being
|
|
exploitable, but will point out vulnerable scripts where it can. If Perl
|
|
detects that it is being applied to a set-id script then it will complain
|
|
loudly that your set-id script is insecure, and won't run it. When Perl
|
|
complains, you need to remove the set-id bit from the script to eliminate
|
|
the vulnerability. Refusing to run the script doesn't in itself close
|
|
the vulnerability; it is just Perl's way of encouraging you to do this.
|
|
|
|
To actually run a script set-id, if you don't have the safe version of
|
|
set-id scripts, you'll need to put a C wrapper around
|
|
the script. A C wrapper is just a compiled program that does nothing
|
|
except call your Perl program. Compiled programs are not subject to the
|
|
kernel bug that plagues set-id scripts. Here's a simple wrapper, written
|
|
in C:
|
|
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#define REAL_PATH "/path/to/script"
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
execv(REAL_PATH, argv);
|
|
fprintf(stderr, "%s: %s: %s\n",
|
|
argv[0], REAL_PATH, strerror(errno));
|
|
return 127;
|
|
}
|
|
|
|
Compile this wrapper into a binary executable and then make I<it> rather
|
|
than your script setuid or setgid. Note that this wrapper isn't doing
|
|
anything to sanitise the execution environment other than ensuring
|
|
that a safe path to the script is used. It only avoids the shebang
|
|
race condition. It relies on Perl's own features, and on the script
|
|
itself being careful, to make it safe enough to run the script set-id.
|
|
|
|
=head2 Protecting Your Programs
|
|
|
|
There are a number of ways to hide the source to your Perl programs,
|
|
with varying levels of "security".
|
|
|
|
First of all, however, you I<can't> take away read permission, because
|
|
the source code has to be readable in order to be compiled and
|
|
interpreted. (That doesn't mean that a CGI script's source is
|
|
readable by people on the web, though.) So you have to leave the
|
|
permissions at the socially friendly 0755 level. This lets
|
|
people on your local system only see your source.
|
|
|
|
Some people mistakenly regard this as a security problem. If your program does
|
|
insecure things, and relies on people not knowing how to exploit those
|
|
insecurities, it is not secure. It is often possible for someone to
|
|
determine the insecure things and exploit them without viewing the
|
|
source. Security through obscurity, the name for hiding your bugs
|
|
instead of fixing them, is little security indeed.
|
|
|
|
You can try using encryption via source filters (Filter::* from CPAN,
|
|
or Filter::Util::Call and Filter::Simple since Perl 5.8).
|
|
But crackers might be able to decrypt it. You can try using the byte
|
|
code compiler and interpreter described below, but crackers might be
|
|
able to de-compile it. You can try using the native-code compiler
|
|
described below, but crackers might be able to disassemble it. These
|
|
pose varying degrees of difficulty to people wanting to get at your
|
|
code, but none can definitively conceal it (this is true of every
|
|
language, not just Perl).
|
|
|
|
If you're concerned about people profiting from your code, then the
|
|
bottom line is that nothing but a restrictive license will give you
|
|
legal security. License your software and pepper it with threatening
|
|
statements like "This is unpublished proprietary software of XYZ Corp.
|
|
Your access to it does not give you permission to use it blah blah
|
|
blah." You should see a lawyer to be sure your license's wording will
|
|
stand up in court.
|
|
|
|
=head2 Unicode
|
|
|
|
Unicode is a new and complex technology and one may easily overlook
|
|
certain security pitfalls. See L<perluniintro> for an overview and
|
|
L<perlunicode> for details, and L<perlunicode/"Security Implications
|
|
of Unicode"> for security implications in particular.
|
|
|
|
=head2 Algorithmic Complexity Attacks
|
|
|
|
Certain internal algorithms used in the implementation of Perl can
|
|
be attacked by choosing the input carefully to consume large amounts
|
|
of either time or space or both. This can lead into the so-called
|
|
I<Denial of Service> (DoS) attacks.
|
|
|
|
=over 4
|
|
|
|
=item *
|
|
|
|
Hash Algorithm - Hash algorithms like the one used in Perl are well
|
|
known to be vulnerable to collision attacks on their hash function.
|
|
Such attacks involve constructing a set of keys which collide into
|
|
the same bucket producing inefficient behavior. Such attacks often
|
|
depend on discovering the seed of the hash function used to map the
|
|
keys to buckets. That seed is then used to brute-force a key set which
|
|
can be used to mount a denial of service attack. In Perl 5.8.1 changes
|
|
were introduced to harden Perl to such attacks, and then later in
|
|
Perl 5.18.0 these features were enhanced and additional protections
|
|
added.
|
|
|
|
At the time of this writing, Perl 5.18.0 is considered to be
|
|
well-hardened against algorithmic complexity attacks on its hash
|
|
implementation. This is largely owed to the following measures
|
|
mitigate attacks:
|
|
|
|
=over 4
|
|
|
|
=item Hash Seed Randomization
|
|
|
|
In order to make it impossible to know what seed to generate an attack
|
|
key set for, this seed is randomly initialized at process start. This
|
|
may be overridden by using the PERL_HASH_SEED environment variable, see
|
|
L<perlrun/PERL_HASH_SEED>. This environment variable controls how
|
|
items are actually stored, not how they are presented via
|
|
C<keys>, C<values> and C<each>.
|
|
|
|
=item Hash Traversal Randomization
|
|
|
|
Independent of which seed is used in the hash function, C<keys>,
|
|
C<values>, and C<each> return items in a per-hash randomized order.
|
|
Modifying a hash by insertion will change the iteration order of that hash.
|
|
This behavior can be overridden by using C<hash_traversal_mask()> from
|
|
L<Hash::Util> or by using the PERL_PERTURB_KEYS environment variable,
|
|
see L<perlrun/PERL_PERTURB_KEYS>. Note that this feature controls the
|
|
"visible" order of the keys, and not the actual order they are stored in.
|
|
|
|
=item Bucket Order Perturbance
|
|
|
|
When items collide into a given hash bucket the order they are stored in
|
|
the chain is no longer predictable in Perl 5.18. This
|
|
has the intention to make it harder to observe a
|
|
collision. This behavior can be overridden by using
|
|
the PERL_PERTURB_KEYS environment variable, see L<perlrun/PERL_PERTURB_KEYS>.
|
|
|
|
=item New Default Hash Function
|
|
|
|
The default hash function has been modified with the intention of making
|
|
it harder to infer the hash seed.
|
|
|
|
=item Alternative Hash Functions
|
|
|
|
The source code includes multiple hash algorithms to choose from. While we
|
|
believe that the default perl hash is robust to attack, we have included the
|
|
hash function Siphash as a fall-back option. At the time of release of
|
|
Perl 5.18.0 Siphash is believed to be of cryptographic strength. This is
|
|
not the default as it is much slower than the default hash.
|
|
|
|
=back
|
|
|
|
Without compiling a special Perl, there is no way to get the exact same
|
|
behavior of any versions prior to Perl 5.18.0. The closest one can get
|
|
is by setting PERL_PERTURB_KEYS to 0 and setting the PERL_HASH_SEED
|
|
to a known value. We do not advise those settings for production use
|
|
due to the above security considerations.
|
|
|
|
B<Perl has never guaranteed any ordering of the hash keys>, and
|
|
the ordering has already changed several times during the lifetime of
|
|
Perl 5. Also, the ordering of hash keys has always been, and continues
|
|
to be, affected by the insertion order and the history of changes made
|
|
to the hash over its lifetime.
|
|
|
|
Also note that while the order of the hash elements might be
|
|
randomized, this "pseudo-ordering" should B<not> be used for
|
|
applications like shuffling a list randomly (use C<List::Util::shuffle()>
|
|
for that, see L<List::Util>, a standard core module since Perl 5.8.0;
|
|
or the CPAN module C<Algorithm::Numerical::Shuffle>), or for generating
|
|
permutations (use e.g. the CPAN modules C<Algorithm::Permute> or
|
|
C<Algorithm::FastPermute>), or for any cryptographic applications.
|
|
|
|
Tied hashes may have their own ordering and algorithmic complexity
|
|
attacks.
|
|
|
|
=item *
|
|
|
|
Regular expressions - Perl's regular expression engine is so called NFA
|
|
(Non-deterministic Finite Automaton), which among other things means that
|
|
it can rather easily consume large amounts of both time and space if the
|
|
regular expression may match in several ways. Careful crafting of the
|
|
regular expressions can help but quite often there really isn't much
|
|
one can do (the book "Mastering Regular Expressions" is required
|
|
reading, see L<perlfaq2>). Running out of space manifests itself by
|
|
Perl running out of memory.
|
|
|
|
=item *
|
|
|
|
Sorting - the quicksort algorithm used in Perls before 5.8.0 to
|
|
implement the sort() function was very easy to trick into misbehaving
|
|
so that it consumes a lot of time. Starting from Perl 5.8.0 a different
|
|
sorting algorithm, mergesort, is used by default. Mergesort cannot
|
|
misbehave on any input.
|
|
|
|
=back
|
|
|
|
See L<https://www.usenix.org/legacy/events/sec03/tech/full_papers/crosby/crosby.pdf> for more information,
|
|
and any computer science textbook on algorithmic complexity.
|
|
|
|
=head2 Using Sudo
|
|
|
|
The popular tool C<sudo> provides a controlled way for users to be able
|
|
to run programs as other users. It sanitises the execution environment
|
|
to some extent, and will avoid the L<shebang race condition|/"Shebang
|
|
Race Condition">. If you don't have the safe version of set-id scripts,
|
|
then C<sudo> may be a more convenient way of executing a script as
|
|
another user than writing a C wrapper would be.
|
|
|
|
However, C<sudo> sets the real user or group ID to that of the target
|
|
identity, not just the effective ID as set-id bits do. As a result, Perl
|
|
can't detect that it is running under C<sudo>, and so won't automatically
|
|
take its own security precautions such as turning on taint mode. Where
|
|
C<sudo> configuration dictates exactly which command can be run, the
|
|
approved command may include a C<-T> option to perl to enable taint mode.
|
|
|
|
In general, it is necessary to evaluate the suitaility of a script to
|
|
run under C<sudo> specifically with that kind of execution environment
|
|
in mind. It is neither necessary nor sufficient for the same script to
|
|
be suitable to run in a traditional set-id arrangement, though many of
|
|
the issues overlap.
|
|
|
|
=head1 SEE ALSO
|
|
|
|
L<perlrun> for its description of cleaning up environment variables.
|