diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 19:43:11 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 19:43:11 +0000 |
commit | fc22b3d6507c6745911b9dfcc68f1e665ae13dbc (patch) | |
tree | ce1e3bce06471410239a6f41282e328770aa404a /upstream/debian-bookworm/man1/perlsec.1 | |
parent | Initial commit. (diff) | |
download | manpages-l10n-fc22b3d6507c6745911b9dfcc68f1e665ae13dbc.tar.xz manpages-l10n-fc22b3d6507c6745911b9dfcc68f1e665ae13dbc.zip |
Adding upstream version 4.22.0.upstream/4.22.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'upstream/debian-bookworm/man1/perlsec.1')
-rw-r--r-- | upstream/debian-bookworm/man1/perlsec.1 | 690 |
1 files changed, 690 insertions, 0 deletions
diff --git a/upstream/debian-bookworm/man1/perlsec.1 b/upstream/debian-bookworm/man1/perlsec.1 new file mode 100644 index 00000000..bc9370b1 --- /dev/null +++ b/upstream/debian-bookworm/man1/perlsec.1 @@ -0,0 +1,690 @@ +.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.43) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +. ds C` +. ds C' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is >0, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.\" +.\" Avoid warning from groff about undefined register 'F'. +.de IX +.. +.nr rF 0 +.if \n(.g .if rF .nr rF 1 +.if (\n(rF:(\n(.g==0)) \{\ +. if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. if !\nF==2 \{\ +. nr % 0 +. nr F 2 +. \} +. \} +.\} +.rr rF +.\" ======================================================================== +.\" +.IX Title "PERLSEC 1" +.TH PERLSEC 1 "2023-11-25" "perl v5.36.0" "Perl Programmers Reference Guide" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +perlsec \- Perl security +.SH "DESCRIPTION" +.IX Header "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. +.SH "SECURITY VULNERABILITY CONTACT INFORMATION" +.IX Header "SECURITY VULNERABILITY CONTACT INFORMATION" +If you believe you have found a security vulnerability in the Perl +interpreter or modules maintained in the core Perl codebase, +email the details to +perl\-security@perl.org <mailto:perl-security@perl.org>. +This address is a closed membership mailing list monitored by the Perl +security team. +.PP +See perlsecpolicy for additional information. +.SH "SECURITY MECHANISMS AND CONCERNS" +.IX Header "SECURITY MECHANISMS AND CONCERNS" +.SS "Taint mode" +.IX Subsection "Taint mode" +By default, +Perl automatically enables a set of special security checks, called \fItaint +mode\fR, 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 \fB\-T\fR command line flag. This flag is +\&\fIstrongly\fR suggested for server programs and any program run on behalf of +someone else, such as a \s-1CGI\s0 script. Once taint mode is on, it's on for +the remainder of your script. +.PP +While in this mode, Perl takes special precautions called \fItaint +checks\fR 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. +.PP +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 +perllocale), results of certain system calls (\f(CW\*(C`readdir()\*(C'\fR, +\&\f(CW\*(C`readlink()\*(C'\fR, the variable of \f(CW\*(C`shmread()\*(C'\fR, the messages returned by +\&\f(CW\*(C`msgrcv()\*(C'\fR, the password, gcos and shell fields returned by the +\&\f(CW\*(C`getpwxxx()\*(C'\fR calls), and all file input are marked as \*(L"tainted\*(R". +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, \fBwith the following exceptions\fR: +.PP +Support for taint checks adds an overhead to all Perl programs, +whether or not you're using the taint features. +Perl 5.18 introduced C preprocessor symbols that can +be used to disable the taint features. +.IP "\(bu" 4 +Arguments to \f(CW\*(C`print\*(C'\fR and \f(CW\*(C`syswrite\*(C'\fR are \fBnot\fR checked for taintedness. +.IP "\(bu" 4 +Symbolic methods +.Sp +.Vb 1 +\& $obj\->$method(@args); +.Ve +.Sp +and symbolic sub references +.Sp +.Vb 2 +\& &{$foo}(@args); +\& $foo\->(@args); +.Ve +.Sp +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 \fBoutside\fR your Perl code, such as POSIX::system, +in which case they are able to run arbitrary external code. +.IP "\(bu" 4 +Hash keys are \fBnever\fR tainted. +.PP +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. +.PP +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 \fBnever\fR tainted. +.PP +For example: +.PP +.Vb 8 +\& $arg = shift; # $arg is tainted +\& $hid = $arg . \*(Aqbar\*(Aq; # $hid is also tainted +\& $line = <>; # Tainted +\& $line = <STDIN>; # Also tainted +\& open FOO, "/home/me/bar" or die $!; +\& $line = <FOO>; # Still tainted +\& $path = $ENV{\*(AqPATH\*(Aq}; # Tainted, but see below +\& $data = \*(Aqabc\*(Aq; # Not tainted +\& +\& system "echo $arg"; # Insecure +\& system "/bin/echo", $arg; # Considered insecure +\& # (Perl doesn\*(Aqt know about /bin/echo) +\& system "echo $hid"; # Insecure +\& system "echo $data"; # Insecure until PATH set +\& +\& $path = $ENV{\*(AqPATH\*(Aq}; # $path now tainted +\& +\& $ENV{\*(AqPATH\*(Aq} = \*(Aq/bin:/usr/bin\*(Aq; +\& delete @ENV{\*(AqIFS\*(Aq, \*(AqCDPATH\*(Aq, \*(AqENV\*(Aq, \*(AqBASH_ENV\*(Aq}; +\& +\& $path = $ENV{\*(AqPATH\*(Aq}; # $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 \*(Aqecho\*(Aq, $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", \*(Aq\-c\*(Aq, $arg; # Very insecure! +\& +\& @files = <*.c>; # insecure (uses readdir() or similar) +\& @files = glob(\*(Aq*.c\*(Aq); # 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\*(Aqt really) +.Ve +.PP +If you try to do something insecure, you will get a fatal error saying +something like \*(L"Insecure dependency\*(R" or \*(L"Insecure \f(CW$ENV\fR{\s-1PATH\s0}\*(R". +.PP +The exception to the principle of \*(L"one tainted value taints the whole +expression\*(R" is with the ternary conditional operator \f(CW\*(C`?:\*(C'\fR. Since code +with a ternary conditional +.PP +.Vb 1 +\& $result = $tainted_value ? "Untainted" : "Also untainted"; +.Ve +.PP +is effectively +.PP +.Vb 5 +\& if ( $tainted_value ) { +\& $result = "Untainted"; +\& } else { +\& $result = "Also untainted"; +\& } +.Ve +.PP +it doesn't make sense for \f(CW$result\fR to be tainted. +.SS "Laundering and Detecting Tainted Data" +.IX Subsection "Laundering and Detecting Tainted Data" +To test whether a variable contains tainted data, and whose use would +thus trigger an \*(L"Insecure dependency\*(R" message, you can use the +\&\f(CW\*(C`tainted()\*(C'\fR function of the Scalar::Util module, available in your +nearby \s-1CPAN\s0 mirror, and included in Perl starting from the release 5.8.0. +Or you may be able to use the following \f(CW\*(C`is_tainted()\*(C'\fR function. +.PP +.Vb 4 +\& sub is_tainted { +\& local $@; # Don\*(Aqt pollute caller\*(Aqs value. +\& return ! eval { eval("#" . substr(join("", @_), 0, 0)); 1 }; +\& } +.Ve +.PP +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. +.PP +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 \f(CW$1\fR, \f(CW$2\fR, 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 \*(L"good\*(R") 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. +.PP +Here's a test to make sure that the data contains nothing but \*(L"word\*(R" +characters (alphabetics, numerics, and underscores), a hyphen, an at sign, +or a dot. +.PP +.Vb 5 +\& if ($data =~ /^([\-\e@\ew.]+)$/) { +\& $data = $1; # $data now untainted +\& } else { +\& die "Bad data in \*(Aq$data\*(Aq"; # log this somewhere +\& } +.Ve +.PP +This is fairly secure because \f(CW\*(C`/\ew+/\*(C'\fR doesn't normally match shell +metacharacters, nor are dot, dash, or at going to mean something special +to the shell. Use of \f(CW\*(C`/.+/\*(C'\fR 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 \fIonly\fR mechanism for +untainting dirty data, unless you use the strategy detailed below to fork +a child of lesser privilege. +.PP +The example does not untaint \f(CW$data\fR if \f(CW\*(C`use locale\*(C'\fR is in effect, +because the characters matched by \f(CW\*(C`\ew\*(C'\fR 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 \f(CW\*(C`\ew\*(C'\fR, put \f(CW\*(C`no locale\*(C'\fR ahead of the expression in the same +block. See \*(L"\s-1SECURITY\*(R"\s0 in perllocale for further discussion and examples. +.ie n .SS "Switches On the ""#!"" Line" +.el .SS "Switches On the ``#!'' Line" +.IX Subsection "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 \f(CW\*(C`\-wU\*(C'\fR instead of \f(CW\*(C`\-w \-U\*(C'\fR +under such systems. (This issue should arise only in Unix or +Unix-like environments that support #! and setuid or setgid scripts.) +.ie n .SS "Taint mode and @INC" +.el .SS "Taint mode and \f(CW@INC\fP" +.IX Subsection "Taint mode and @INC" ++When the taint mode (\f(CW\*(C`\-T\*(C'\fR) is in effect, the environment variables ++\f(CW\*(C`PERL5LIB\*(C'\fR, \f(CW\*(C`PERLLIB\*(C'\fR, and \f(CW\*(C`PERL_USE_UNSAFE_INC\*(C'\fR +are ignored by Perl. You can still adjust \f(CW@INC\fR from outside the +program by using the \f(CW\*(C`\-I\*(C'\fR command line option as explained in +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 \f(CW\*(C`\-I\*(C'\fR option is clearly +visible and therefore permitted. +.PP +Another way to modify \f(CW@INC\fR without modifying the program, is to use +the \f(CW\*(C`lib\*(C'\fR pragma, e.g.: +.PP +.Vb 1 +\& perl \-Mlib=/foo program +.Ve +.PP +The benefit of using \f(CW\*(C`\-Mlib=/foo\*(C'\fR over \f(CW\*(C`\-I/foo\*(C'\fR, is that the former +will automagically remove any duplicated directories, while the latter +will not. +.PP +Note that if a tainted string is added to \f(CW@INC\fR, the following +problem will be reported: +.PP +.Vb 1 +\& Insecure dependency in require while running with \-T switch +.Ve +.PP +On versions of Perl before 5.26, activating taint mode will also remove +the current directory (\*(L".\*(R") from the default value of \f(CW@INC\fR. Since +version 5.26, the current directory isn't included in \f(CW@INC\fR by +default. +.SS "Cleaning Up Your Path" +.IX Subsection "Cleaning Up Your Path" +For "Insecure \f(CW$ENV{PATH}\fR" messages, you need to set \f(CW$ENV{\*(AqPATH\*(Aq}\fR 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 \fInot\fR generated because you didn't supply a full path +to the program; instead, it's generated because you never set your \s-1PATH\s0 +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 \s-1PATH,\s0 it makes sure you set the \s-1PATH.\s0 +.PP +The \s-1PATH\s0 isn't the only environment variable which can cause problems. +Because some shells may use the variables \s-1IFS, CDPATH, ENV,\s0 and +\&\s-1BASH_ENV,\s0 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. +.PP +.Vb 1 +\& delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; # Make %ENV safer +.Ve +.PP +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 \fBafter\fR 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. +.PP +Perl does not call the shell to expand wild cards when you pass \f(CW\*(C`system\*(C'\fR +and \f(CW\*(C`exec\*(C'\fR explicit parameter lists instead of strings with possible shell +wildcards in them. Unfortunately, the \f(CW\*(C`open\*(C'\fR, \f(CW\*(C`glob\*(C'\fR, and +backtick functions provide no such alternate calling convention, so more +subterfuge will be required. +.PP +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 +\&\f(CW\*(C`open\*(C'\fR syntax that connects the parent and child by a pipe. Now the +child resets its \s-1ID\s0 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 \f(CW\*(C`open\*(C'\fR 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. +.PP +Here's a way to do backticks reasonably safely. Notice how the \f(CW\*(C`exec\*(C'\fR 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. +.PP +.Vb 10 +\& use English; +\& die "Can\*(Aqt 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\*(Aqt drop privileges" +\& unless $UID == $EUID && $GID eq $EGID; +\& $ENV{PATH} = "/bin:/usr/bin"; # Minimal PATH. +\& # Consider sanitizing the environment even more. +\& exec \*(Aqmyprog\*(Aq, \*(Aqarg1\*(Aq, \*(Aqarg2\*(Aq +\& or die "can\*(Aqt exec myprog: $!"; +\& } +.Ve +.PP +A similar strategy would work for wildcard expansion via \f(CW\*(C`glob\*(C'\fR, although +you can use \f(CW\*(C`readdir\*(C'\fR instead. +.PP +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 \s-1CGI\s0 programs. +.PP +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, \*(L"Here, +run this.\*(R" 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. +.SS "Shebang Race Condition" +.IX Subsection "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. +.PP +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 \fI/dev/fd/3\fR. 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 \f(CW\*(C`\-DSETUID_SCRIPTS_ARE_SECURE_NOW\*(C'\fR. The \fIConfigure\fR +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 \s-1BSD 4.4\s0 use this approach to avoid the kernel race condition. +.PP +If you don't have the safe version of set-id scripts, all is not lost. +Sometimes this kernel \*(L"feature\*(R" 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. +.PP +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. +.PP +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: +.PP +.Vb 4 +\& #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\en", +\& argv[0], REAL_PATH, strerror(errno)); +\& return 127; +\& } +.Ve +.PP +Compile this wrapper into a binary executable and then make \fIit\fR 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. +.SS "Protecting Your Programs" +.IX Subsection "Protecting Your Programs" +There are a number of ways to hide the source to your Perl programs, +with varying levels of \*(L"security\*(R". +.PP +First of all, however, you \fIcan't\fR 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 \s-1CGI\s0 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. +.PP +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. +.PP +You can try using encryption via source filters (Filter::* from \s-1CPAN,\s0 +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). +.PP +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 \*(L"This is unpublished proprietary software of \s-1XYZ\s0 Corp. +Your access to it does not give you permission to use it blah blah +blah.\*(R" You should see a lawyer to be sure your license's wording will +stand up in court. +.SS "Unicode" +.IX Subsection "Unicode" +Unicode is a new and complex technology and one may easily overlook +certain security pitfalls. See perluniintro for an overview and +perlunicode for details, and \*(L"Security Implications +of Unicode\*(R" in perlunicode for security implications in particular. +.SS "Algorithmic Complexity Attacks" +.IX Subsection "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 +\&\fIDenial of Service\fR (DoS) attacks. +.IP "\(bu" 4 +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. +.Sp +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: +.RS 4 +.IP "Hash Seed Randomization" 4 +.IX 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 \s-1PERL_HASH_SEED\s0 environment variable, see +\&\*(L"\s-1PERL_HASH_SEED\*(R"\s0 in perlrun. This environment variable controls how +items are actually stored, not how they are presented via +\&\f(CW\*(C`keys\*(C'\fR, \f(CW\*(C`values\*(C'\fR and \f(CW\*(C`each\*(C'\fR. +.IP "Hash Traversal Randomization" 4 +.IX Item "Hash Traversal Randomization" +Independent of which seed is used in the hash function, \f(CW\*(C`keys\*(C'\fR, +\&\f(CW\*(C`values\*(C'\fR, and \f(CW\*(C`each\*(C'\fR 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 \f(CW\*(C`hash_traversal_mask()\*(C'\fR from +Hash::Util or by using the \s-1PERL_PERTURB_KEYS\s0 environment variable, +see \*(L"\s-1PERL_PERTURB_KEYS\*(R"\s0 in perlrun. Note that this feature controls the +\&\*(L"visible\*(R" order of the keys, and not the actual order they are stored in. +.IP "Bucket Order Perturbance" 4 +.IX 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 \s-1PERL_PERTURB_KEYS\s0 environment variable, see \*(L"\s-1PERL_PERTURB_KEYS\*(R"\s0 in perlrun. +.IP "New Default Hash Function" 4 +.IX Item "New Default Hash Function" +The default hash function has been modified with the intention of making +it harder to infer the hash seed. +.IP "Alternative Hash Functions" 4 +.IX 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. +.RE +.RS 4 +.Sp +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 \s-1PERL_PERTURB_KEYS\s0 to 0 and setting the \s-1PERL_HASH_SEED\s0 +to a known value. We do not advise those settings for production use +due to the above security considerations. +.Sp +\&\fBPerl has never guaranteed any ordering of the hash keys\fR, 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. +.Sp +Also note that while the order of the hash elements might be +randomized, this \*(L"pseudo-ordering\*(R" should \fBnot\fR be used for +applications like shuffling a list randomly (use \f(CW\*(C`List::Util::shuffle()\*(C'\fR +for that, see List::Util, a standard core module since Perl 5.8.0; +or the \s-1CPAN\s0 module \f(CW\*(C`Algorithm::Numerical::Shuffle\*(C'\fR), or for generating +permutations (use e.g. the \s-1CPAN\s0 modules \f(CW\*(C`Algorithm::Permute\*(C'\fR or +\&\f(CW\*(C`Algorithm::FastPermute\*(C'\fR), or for any cryptographic applications. +.Sp +Tied hashes may have their own ordering and algorithmic complexity +attacks. +.RE +.IP "\(bu" 4 +Regular expressions \- Perl's regular expression engine is so called \s-1NFA\s0 +(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 \*(L"Mastering Regular Expressions\*(R" is required +reading, see perlfaq2). Running out of space manifests itself by +Perl running out of memory. +.IP "\(bu" 4 +Sorting \- the quicksort algorithm used in Perls before 5.8.0 to +implement the \fBsort()\fR 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. +.PP +See <https://www.usenix.org/legacy/events/sec03/tech/full_papers/crosby/crosby.pdf> for more information, +and any computer science textbook on algorithmic complexity. +.SS "Using Sudo" +.IX Subsection "Using Sudo" +The popular tool \f(CW\*(C`sudo\*(C'\fR 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 shebang race condition. If you don't have the safe version of set-id scripts, +then \f(CW\*(C`sudo\*(C'\fR may be a more convenient way of executing a script as +another user than writing a C wrapper would be. +.PP +However, \f(CW\*(C`sudo\*(C'\fR sets the real user or group \s-1ID\s0 to that of the target +identity, not just the effective \s-1ID\s0 as set-id bits do. As a result, Perl +can't detect that it is running under \f(CW\*(C`sudo\*(C'\fR, and so won't automatically +take its own security precautions such as turning on taint mode. Where +\&\f(CW\*(C`sudo\*(C'\fR configuration dictates exactly which command can be run, the +approved command may include a \f(CW\*(C`\-T\*(C'\fR option to perl to enable taint mode. +.PP +In general, it is necessary to evaluate the suitability of a script to +run under \f(CW\*(C`sudo\*(C'\fR 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. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\*(L"\s-1ENVIRONMENT\*(R"\s0 in perlrun for its description of cleaning up environment +variables. |