将任意变量括在单引号中是否会阻止 eval() 执行代码?

Does enclosing an arbitrary variable in single quotes prevent eval() from executing code?

我正在尝试向我的同事展示在 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 是邪恶的,假设用单引号括起任意输入会阻止它退出是否正确

所以在 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++;
    }
}
?>