用一个单引号引起来的任意变量是否会阻止eval()执行代码?

时间:2018-06-22 17:10:56

标签: php eval

我正在向同事们演示在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是邪恶的,假设将任意输入括在单引号中会阻止它被射出,这是否正确?

1 个答案:

答案 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++;
    }
}
?>