How can I safely use eval in php?
I know some people may just respond "never" as long as there's user input. But suppose I have something like this:
$version = $_REQUEST['version']; $test = 'return $version > 3;'; $success = eval($test);
This is obviously a simplified case, but is there anything that a user can input as version to get this to do something malicious? If I restrict the type of strings that $test can take on to comparing the value of certain variables to other variables, is there any way anybody can see to exploit that?
I've tried running the following script on the server and nothing happens:
<?php $version = "exec('mkdir test') + 4"; $teststr = '$version > 3;'; $result = eval('return ' . $teststr); var_dump($result); ?>
all I get is bool(false). No new directory is created. If I have a line that actually calls exec('mkdir test') before that, it actually does create the directory. It seems to be working correctly, in that it's just comparing a string converted to a number to another number and finding out the result is false.
If you do this. Only accept ints.
If you must accept strings, don't.
If you still think you must. Don't!
And lastly, if you still, after that, think you need strings. JUST DON'T!
$version = "exec('rm-rf/...') + 4"; // Return 4 so the return value is "true" // after all, we're gentlemen! $test = "return $version > 3"; eval($test);
You would have to do at least a filter_var() or is_numeric() on the input value in this case.
By the way, the way you use eval (assigning its result to $success) doesn't work in PHP. You would have to put the assignment into the eval()ed string.
yes, anything. I would use $version = (int)$_REQUEST['version']; to validate the data.
The way to make this safe would be to ensure that $version is a number BEFORE you try to eval.
You need to be more precise with your definitions of "malicious" or "safe". Consider for example
exec("rm -rf /"); echo "enlarge your rolex!"; while(true) echo "*";
all three snippets are "malicious" from the common sense point of view, however technically they are totally different. Protection techniques that may apply to #1, won't work with other two and vice versa.
Use this code to remove everything except numbers (0-9): preg_replace('/[^0-9]+/', '', $version);