Perl Cd Bookshelf [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Perl Cd Bookshelf [Electronic resources] - نسخه متنی

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید

19.5. Executing Commands Without Shell Escapes


19.5.1. Problem


You need to use a
user''s input as part of a command, but you don''t want to allow the
user to trick the shell into running other commands or looking at
other files. If you just blindly call the system
function or backticks on a single string containing a command line
derived from untested user input, the shell might be used to run the
command. This would be unsafe.

19.5.2. Solution


Unlike its single-argument version, the list form of the
system function is safe from shell escapes. When
the command''s arguments involve user input from a form, never use
this:

system("command $input @files");            # UNSAFE

Write it this way instead:

system("command", $input, @files);          # safer

19.5.3. Discussion


Because Perl was designed as a glue language, it''s easy to use it to
call other programs—too easy, in some cases.

If you''re merely trying to run a shell command but don''t need to
capture its output, it''s easy enough to call
system using its multiple argument form. But what
happens if you''re using the command in backticks or as part of a
piped open? Now you have a real problem, because those don''t permit
the multiple argument form that system does. The
solution (prior to v5.8; see later in this Discussion) is to manually
fork and exec the child
processes on your own. It''s more work, but at least stray shell
escapes won''t be ruining your
day.

It''s safe to use backticks in a CGI script only if the arguments you
give the program are internally generated, as in:

chomp($now = `date`);

But if the command within the backticks contains user-supplied input,
perhaps like this:

@output = `grep $input @files`;

you have to be much more careful.

die "cannot fork: $!" unless defined ($pid = open(SAFE_KID, "-|"));
if ($pid = = 0) {
exec(''grep'', $input, @files) or die "can''t exec grep: $!";
} else {
@output = <SAFE_KID>;
close SAFE_KID; # $? contains status
}

This works because exec, like
system, permits a calling convention that''s immune
to shell escapes. When passed a list, no shell is called, and so no
escapes can occur.

Similar circumlocutions are needed when using open
to start up a command. Here''s a safe backtick or piped open for read.
Instead of using this unsafe code:

open(KID_TO_READ, "$program @options @args |");    # UNSAFE

use this more complicated but safer code:

# add error processing as above
die "cannot fork: $!" unless defined($pid = open(KID_TO_READ, "-|"));
if ($pid) { # parent
while (<KID_TO_READ>) {
# do something interesting
}
close(KID_TO_READ) or warn "kid exited $?";
} else { # child
# reconfigure, then
exec($program, @options, @args) or die "can''t exec program: $!";
}

Here''s a safe piped open for writing. Instead of using this unsafe
code:

open(KID_TO_WRITE, "|$program $options @args");   # UNSAFE

use this more complicated but safer code:

die "cannot fork: $!" unless defined($pid = open(KID_TO_WRITE, "-|"));
$SIG{PIPE} = sub { die "whoops, $program pipe broke" };
if ($pid) { # parent
for (@data) { print KID_TO_WRITE $_ }
close(KID_TO_WRITE) or warn "kid exited $?";
} else { # child
# reconfigure, then
exec($program, @options, @args) or die "can''t exec program: $!";
}

Put any extra security measures you''d like where the comment in the
code says reconfigure. You can change environment
variables, reset temporary user or group ID values, change
directories or umasks, etc. You''re in the child process now, where
changes won''t propagate back to the parent.

If you don''t have any reconfiguration to do in the child process, and
you''re running at least the v5.8 release of Perl,
open supports a list of separate parameters that
works as system and exec do
when passed a list; that is, it avoids the shell altogether. Those
two calls would be:

open(KID_TO_READ, "-|", $program, @options, @args)
|| die "can''t run $program: $!";

and:

open(KID_TO_WRITE, "|-", $program, $options, @args)
|| die "can''t run $program: $!";

This doesn''t help you, of course, if you run a setuid program that
can be exploited with the data you give it. The mail program
sendmail is a setuid program commonly run from
CGI scripts. Know the risks before you call
sendmail or any other setuid program.

19.5.4. See Also


The system, exec, and
open functions in Chapter 29 of
Programming Perl and in
perlfunc(1); the section on "Talking to
Yourself" in Chapter 16 of Programming Perl;
the section on "Accessing Commands and Files Under Reduced Privilege"
in Chapter 23 of Programming Perl;
perlsec(1); Recipe 16.1;
Recipe 16.2; Recipe 16.3

/ 875