我正在向同事们演示在PHP中使用eval()
的危险。
在一段代码中,我发现了类似的东西(这非常简化):
<?php
$i = 0;
foreach ($_GET as $key => $value) {
if (strpos($key, 'arg') !== false) {
eval('$data' . $i . '=$value;');
$i++;
}
}
当然我告诉他们这应该改写为
<?php
$i=0;
foreach ($_GET as $key => $value) {
if (strpos($key, 'arg') !== false) {
$varname = 'data' . $i;
$$varname = $value;
$i++;
}
}
此外,他们应该为此使用关联数组。
但是,我无法真正说明为什么使用eval容易导致任意代码执行。似乎将变量括在单引号中不会执行代码。
我试图给他们看类似的东西:
http://localhost/eval.php?arg=var_dump($_ENV);&arg2=phpinfo():
似乎参数被清除而不是执行,因此数组中填充了无害的字符串。
因此,即使每个人都认为eval是邪恶的,假设将任意输入括在单引号中会阻止它被射出,这是否正确?
答案 0 :(得分:1)
因此在PHP single quotes are different from double quotes中,变量不会自动替换为字符串文字。在您的示例中,这使eval()(相对)安全,因为您要引用$ value,这是由foreach提供的字符串变量。在每种情况下,您实际上都是在执行:
$data0 = $value;
这应该是相当安全的,因为攻击者无法指定所评估的内容。如果使用双引号将字符串替换为eval()之前的字符串,这将导致恶意代码运行。这不会使eval()变得安全,但确实适用于此示例。
这是用单引号重新编写的示例,该示例将导致运行恶意代码:
<?php
$i = 0;
foreach ($_GET as $key => $value) {
if (strpos($key, 'arg') !== false) {
(eval('$data' . $i . '=' . $value . ';'));
$i++;
}
}
?>