📄 ch11.htm
字号:
dangerous variable paths. Of course, testing and being a little
on the paranoid side does help in flushing out security holes.
Ask yourself this question when testing scripts for security violations:
If I were a hacker, is there any way I can use this script to
break into my system?
<H2><A NAME="SomeTipsonMakingScriptsSecure"><FONT SIZE=5 COLOR=#FF0000>Some
Tips on Making Scripts Secure</FONT></A></H2>
<P>
The first thing to do when making a Perl script secure is to set
the effective user and group <TT><FONT FACE="Courier">id</FONT></TT>s
to the same as the real user and group <TT><FONT FACE="Courier">id</FONT></TT>s
of the process. This is done with the following lines, which should
be placed before any calls that manipulate files or directories:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">$> = $< # set effective user
Ids to real id.<BR>
$) = $( # set group id to real id.</FONT></TT>
</BLOCKQUOTE>
<P>
Next, make sure that you reset at least these two environment
variables to a known value:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">$ENV{'PATH'} = '/bin:/usr/bin';<BR>
$ENV{'IFS'} = '' if $ENV{'IFS'} ne '';</FONT></TT>
</BLOCKQUOTE>
<P>
Force the path to a known value so that unknown programs cannot
be inserted and executed from writable locations in the path.
The <TT><FONT FACE="Courier">IFS</FONT></TT> field is set to a
<TT><FONT FACE="Courier">null</FONT></TT> value to prevent any
misuse of inter-field characters.
<P>
Another thing to do is to explicitly create your own strings rather
than use strings expanded by the shell. If you are making a call
to <TT><FONT FACE="Courier">exec</FONT></TT>, pass each argument
explicitly, not as a complete string that could have been tainted
by the caller's shell program. For example, avoid the use of a
statement like this:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">exec 'myprog @arglist';</FONT></TT>
</BLOCKQUOTE>
<P>
Instead, use statements like this one:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">exec 'myprog', 'arg1', 'arg2', 'arg3';</FONT></TT>
</BLOCKQUOTE>
<P>
This prevents someone from sending more than one argument to a
program. You can use the Perl <TT><FONT FACE="Courier">system()</FONT></TT>,
which like <TT><FONT FACE="Courier">exec()</FONT></TT>, calls
without invoking a shell by supplying more than one argument:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">system('/usr/bin/ls', '-a');</FONT></TT>
</BLOCKQUOTE>
<P>
Pipes are a potential leak in systems, as well. You can use the
<TT><FONT FACE="Courier">open()</FONT></TT> call to get the same
functionality as <TT><FONT FACE="Courier">popen()</FONT></TT>
(but without starting a shell) with a call of the form:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">open(FH, '|-') || exec("program",
$arg1, $arg2);</FONT></TT>
</BLOCKQUOTE>
<P>
Finally, whenever you are dealing with pathnames, be sure to check
for the <TT><FONT FACE="Courier">..</FONT></TT> component. The
seemingly safe line to get <TT><FONT FACE="Courier">man</FONT></TT>
pages via HTML pages can be exploited, too. Consider this line:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">open(MANPAGE, "/usr/man/man1/$filename$section");</FONT></TT>
</BLOCKQUOTE>
<P>
You can get to the password file if the user-supplied filename
has <TT><FONT FACE="Courier">$filename</FONT></TT> set to <TT><FONT FACE="Courier">../../../etc/passwd</FONT></TT>
and <TT><FONT FACE="Courier">$section = " "</FONT></TT>.
Check to see whether the filename has <TT><FONT FACE="Courier">..</FONT></TT>
in it for abuse at the server side. Don't process filenames that
make you traverse upwards. Use explicit, full pathnames wherever
possible.
<P>
There is a time lag between the point where a kernel determines
whether a script is <TT><FONT FACE="Courier">setuid</FONT></TT>
and the time the Perl interpreter executes the script. The script
could be a symbolic link and therefore can be modified during
this time interval. It's hard to do, but not impossible.
<P>
Some kernels do not allow <TT><FONT FACE="Courier">setuid</FONT></TT>
scripts, period. This is somewhat too limiting in most systems
because such a blanket order prevents you from doing even legitimate
tasks. The other route is to simply ignore the <TT><FONT FACE="Courier">setuid</FONT></TT>
bit setting in the kernel and run only at user level. You can
still use the built-in Perl mechanism to emulate the <TT><FONT FACE="Courier">setuid</FONT></TT>
behavior. However, if the kernel allows you to run <TT><FONT FACE="Courier">setuid</FONT></TT>
scripts as root, and the bit is set, Perl will display a warning
message about security. At this point, either disable the Perl
script or call it from a C program.
<H2><A NAME="ThePerlSafepmModule"><FONT SIZE=5 COLOR=#FF0000>The
Perl </FONT><TT><FONT SIZE=5 COLOR=#FF0000 FACE="Courier">Safe.pm</FONT></TT><FONT SIZE=5 COLOR=#FF0000>
Module</FONT></A></H2>
<P>
The Perl <TT><FONT FACE="Courier">Safe.pm</FONT></TT> module is
written by Malcolm Beattie (<TT><FONT FACE="Courier">mbeattie@sable.ox.ac.uk</FONT></TT>)
and is designed to test Perl code to see how it will work in the
real world. The <TT><FONT FACE="Courier">Safe</FONT></TT> extension
module creates two "compartments" in which code can
be tested. A <I>compartment</I> is simply a known environment
that does not allow system access.
<P>
A compartment has a name space other than <TT><FONT FACE="Courier">main::</FONT></TT>.
Any variables declared in the new name space cannot access variables
outside this name space. Added to this name space wrapper is the
notion of an operator mask. Basically, an operator mask is an
array of elements, each with a value of <TT><FONT FACE="Courier">0</FONT></TT>
or <TT><FONT FACE="Courier">1</FONT></TT>, indicating which operators
Perl can use and which operators it cannot use. Therefore, most
global variables are shielded from the wrapped section of code
in a <TT><FONT FACE="Courier">Safe</FONT></TT> object.
<P>
The special variables <TT><FONT FACE="Courier">$_</FONT></TT>,<B>
</B><TT><FONT FACE="Courier">@_</FONT></TT>,<B> </B><TT><FONT FACE="Courier">_</FONT></TT>,
and <TT><FONT FACE="Courier">%_</FONT></TT> are still available
to the wrapped section of code. In fact, these special variables
are also shared between different enclosed name spaces. The requirement
to allow these variables to be shared is necessary to allow parameter
passing between subroutines in a wrapped code section.
<H3><A NAME="UsingtheSafeClass">Using the <TT><FONT SIZE=4 FACE="Courier">Safe</FONT></TT><FONT SIZE=4>
Class</FONT></A></H3>
<P>
To use the <TT><FONT FACE="Courier">Safe</FONT></TT> class, you
have to take the following steps:
<UL>
<LI><FONT COLOR=#000000>Create a compartment.</FONT>
<LI><FONT COLOR=#000000>Perform unsafe operations using the compartment.</FONT>
<LI><FONT COLOR=#000000>When unsafe operations are over, delete
the partition.</FONT>
</UL>
<P>
A new compartment is created using a new <TT><FONT FACE="Courier">Safe</FONT></TT>
object. Both arguments to the call to create a <TT><FONT FACE="Courier">Safe</FONT></TT>
object are optional in the syntax shown here:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">$cpt = new Safe( $namespace, $mask );</FONT></TT>
</BLOCKQUOTE>
<P>
where<TT><FONT FACE="Courier"> $namespace</FONT></TT> is the root
name space to use instead of <TT><FONT FACE="Courier">main::</FONT></TT>.
If you do not specify this name space, the default name of <TT><FONT FACE="Courier">Safe::Root000000000</FONT></TT>
is used. The zeroes in the number portion of the default name
space are incremented on the creation of every new name space
object. This way you can have separate name spaces for separate
modules.
<P>
The operator mask to use is simply an array of <TT><FONT FACE="Courier">MAXO</FONT></TT>
integers. The value of <TT><FONT FACE="Courier">MAXO</FONT></TT>
is the number of operators in your Perl interpreter. Each element
of the array maps to a Perl operator and has the value of <TT><FONT FACE="Courier">0</FONT></TT>
or <TT><FONT FACE="Courier">1</FONT></TT>. If an element is <TT><FONT FACE="Courier">1</FONT></TT>,
the Perl operator is not permitted to execute; a value of <TT><FONT FACE="Courier">0</FONT></TT>
for an element allows Perl to execute that operator. Therefore,
by judiciously setting the mask elements, you can specify which
commands to execute in your Perl program.
<P>
The default value of the operator mask removes all system and
file operations. Therefore, by default, you cannot create, write
to, or remove files and directories. Interprocess communication
operations are not permitted either. However, input/output operations
via pipes and reading from <TT><FONT FACE="Courier">stdin</FONT></TT>
and writing to <TT><FONT FACE="Courier">stdout</FONT></TT> are
permitted. Any file handles passed into the file handle are considered
secure and any operations on handles that are already opened are
also allowed.
<P>
The <TT><FONT FACE="Courier">Safe</FONT></TT> module file contains
routines for mapping operator names into the operator <TT><FONT FACE="Courier">mask</FONT></TT>
and <TT><FONT FACE="Courier">back</FONT></TT>. Once you have the
object, you can perform the following operations on it:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">$namespace = $secure->root() # returns
the namespace</FONT></TT>
</BLOCKQUOTE>
<P>
To set the name space to a new value, pass the name in the argument
list:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">$newName = "krago"<BR>
$secure->root($newName);</FONT></TT>
</BLOCKQUOTE>
<P>
The mask can be retrieved and reset using the following method
from outside the wrapped code. The following code disallows all
shared memory operations, but allows any messaging facilities:
<BLOCKQUOTE>
<TT><FONT FACE="Courier">require Safe;<BR>
$secure = new Safe;<BR>
<BR>
@defMask = $secure->mask(); #
get the mask<BR>
$secure->trap(OP_SHMGET,OP_SHMCTL,OP_SHMREAD,OP_SHMWRITE);
<BR>
$secure->untrap(OP_MSGCTL,OP_MSGGET,OP_MSGSND,OP_MSGRCV);<BR>
$secure->mask(@defmask);<BR>
<BR>
open(DBFILE,'myCredit.File') || die " Whoa! Canna open Kaptain!";
<BR>
<BR>
sub safecode {<BR>
</FONT></TT> <TT><FONT FACE="Courier">
#<BR>
# Open database and do credit card transaction.
<BR>
</FONT></TT> <TT><FONT FACE="Courier">
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -