Question about "eval" security

R

Randal L. Schwartz

Richard> Don't use eval, use something like

Richard> my %var = (
Richard> 'foo' => ...,
Richard> 'bar' => ...,
Richard> );

Richard> $userinput =~ s[ \$ ( \w+ ) ][ $var{ $1 } ]xeg;

You don't need the "e" there, and it becomes less scary, if you simply:

$userinput =~ s[ \$ ( \w+ ) ][$var{ $1 }]xg;


print "Just another Perl hacker,"
 
H

H. Nakanishi

I wish to use "eval" on a user input but want to make sure security is not
compromised. What I want is just to allow variable interpolation but not any
executions. Would something like:

eval qq/"$userinput"/;

work? As far as I could test it, it seems to do the job (i.e., does evaluate
any valid variables in $userinput but refuse to execute any commands in it.
(If I take the double quotes out, then it would execute commands - which is
very bad. I want to make sure that this is OK as far as security.

Thanks in advance.
H. Nakanishi
 
T

Tad McClellan

H. Nakanishi said:
I wish to use "eval" on a user input


Why do you wish to use "eval" on a user input?

That is a very dangerous thing to wish for (especially in a
university environment).

You can nearly always redesign your application so that you can
get what you want without resorting to the evil eval EXPR.

but want to make sure security is not
compromised.


Then you have enabled taint checking already?

What I want is just to allow variable interpolation but not any
executions.


Interpoloation _does_ allow "executions"...

Would something like:

eval qq/"$userinput"/;

work?

No.


As far as I could test it, it seems to do the job (i.e., does evaluate
any valid variables in $userinput but refuse to execute any commands in it.


Try it with:

my $userinput = '@{[ print q(ouch!) ]}';

then pretend it said unlink( <* .*> ) instead of print()...

See "perldoc -q expand" for what is going on there.

I want to make sure that this is OK as far as security.


The proper way to go about it is to decide what you want to allow,
and then write a pattern match that will match only those things
that you want to allow.

This is almost for sure an XY-problem.

What is it that you really want to accomplish? We can probably help
you do that _without_ eval()...
 
R

Richard Voss

H. Nakanishi said:
I wish to use "eval" on a user input but want to make sure security is not
compromised. What I want is just to allow variable interpolation but not any
executions. Would something like:

Don't use eval, use something like

my %var = (
'foo' => ...,
'bar' => ...,
);

$userinput =~ s[ \$ ( \w+ ) ][ $var{ $1 } ]xeg;


If you want it more sophisticated, use an existing template engine that allows
access to various datastructures, object methods, basic programming (conditional
statements, loops), e.g. Template Toolkit. search.cpan.org!
eval qq/"$userinput"/;

$userinput = q{
removing all your files returned ". system('rm -r /') . ", thanks
};

oops, and there are _lots_ of ways to do that.
work? As far as I could test it, it seems to do the job (i.e., does evaluate
any valid variables in $userinput but refuse to execute any commands in it.

You should invest more effort into developing good tests :)
 
C

Chesucat

Thanks to Randal and Richard for their help. I will use:

$userinput =~ s/\$(\w+)/${$1}/g;

instead. Are there any problems with this?

userinput matches and substitute a dollar and one or more any word to the
end of the string, put one or more any word into variable one and discards
the rest globally. No! That make perfect sense to me, but I am just NOT
a perl hacker!;-)

chesucat
 
B

Bart Lateur

H. Nakanishi said:
Would something like:

eval qq/"$userinput"/;

work?

Not if the input contains quotes.
What I want is just to allow variable interpolation but not any
executions.

Then perhaps String::Interpolate can be of use. See CPAN.
I want to make sure that this is OK as far as security.

Not really... as Randal Schwartz demonstrated. You could look into
safe.pm AKA safe on your local system with perldoc, or on CPAN
 
N

nobull

Bart Lateur said:
Not if the input contains quotes.

That's why the standard way to write this is

chop( my $string = eval "<<end_of_data\n$userinput\nend_of_data\n");

This this technique is totally inappropriate if $userinput is ever
going to come from someone to whom you wouldn't grant the right to run
their own scripts. So for the OP it is useless.

It also fuzzes the line between data and program. This can be bad and
is something you shouldn't do without careful consideration. On the
other hand it's not nearly as bad as some people would have you
believe.

I've been trying to get this explaination into the FAQ for years. The
_question_ is in the FAQ but the current version of FAQ patronisingly
withholds the answer. So that when people "discover" it for themselves
as the OP did in this case:

1) They don't come up with the here-doc trick.
2) They are not alerted to the downsides.
3) They loose trust in the FAQ.

Worse still, the advice in the FAQ is "roll your own templating
system" without so much as a mention of the fact that there are one or
two templating systems out there already.
Then perhaps String::Interpolate can be of use. See CPAN.

No, String::Interpolate is useful if you _do_ want to allow executions
but want to attempt to corral them a bit.

Note however that the security of String::Interpolate relies on Safe
and Safe is known to have security holes. String::Interpolate plugs
several of them but I (who wrote it) would not trust
String::Interpolate as protection against anything but a causual
attacker.
 
H

H. Nakanishi

H> Thanks to Randal and Richard for their help. I will use:
H> $userinput =~ s/\$(\w+)/${$1}/g;

H> instead. Are there any problems with this?

Yes, don't use soft references! Don't mix user data with program
data.

I see that in principle one shouldn't mix user data with program data.
However, I don't see any danger as long as only certain variable names
have values assigned to them within the subprogram where this statement
will be used. The question was whether any command would be executed
if $userinput contained one. Would it be?
Create a hash %vars, and populate it with your user data. Then use:

$userinput =~ s/\$(\w+)/$vars{$1}/g;

I ended up doing this, which is indeed cleaner in terms of separating
user data and program data. So thanks for this, Richard and Randal.
The reason for initially resisting this was because the actual variables
which I would like to use assigned values for in $userinput are only
dynamically determined (from other program data, but only at run time)
and thus I thought constructing my(%var) might be difficult. It wasn't.
So that is a moot point now.

I thank all who took interest in my original question. Since I did end up,
I think, with a safer and cleaner code as a result of posting the question,
I am glad I did it. However, I must say that some posters, while
ultimately being helpful, have ways of exuding a sense of "holier than
thou".

H. Nakanishi
 
T

Ted Zlatanov

I wish to use "eval" on a user input but want to make sure security
is not compromised. What I want is just to allow variable
interpolation but not any executions. Would something like:

eval qq/"$userinput"/;

work? As far as I could test it, it seems to do the job (i.e., does
evaluate any valid variables in $userinput but refuse to execute any
commands in it. (If I take the double quotes out, then it would
execute commands - which is very bad. I want to make sure that this
is OK as far as security.

I would design a syntax that can be parsed, either with Perl, with a
module like AppConfig, or with a parser like Parse::RecDescent.
AppConfig in particular allows you to interpolate, but the variables
have to be pre-defined for AppConfig usage, or %ENV keys. So you
can't interpolate just any variable you want. I consider this a good
thing.

What are your basic operations? Let's say you need to get/set
scalars; give your users these commands (also see AppConfig's built-in
syntax for ideas on hashes and lists):

(set)
VAR = value # just set it to a value
VAR1 = $VAR2 # copy the value from another variable

(get)
VAR

And that's all they are allowed to do. This is the safest route in
terms of security, because you are not allowing your users to do
anything unexpected. Calling eval() can produce unexpected results if
you don't control the input tightly. Tight input control can be just
as costly as a custom syntax, if not worse, in terms of security and
development time (primary and bug-fixing when holes are discovered).

Of course, if the user input has to allow very complex Perl operations
and if you trust the input, use eval() as shown by the other replies
to your message. That doesn't seem to be the case from your post,
though.

Ted
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,125
Messages
2,570,748
Members
47,302
Latest member
MitziWragg

Latest Threads

Top