如何使用extract安全地创建PHP变量

时间:2011-05-16 21:37:56

标签: php extract

在我之前的帖子中,我问如何从数组创建变量(PHP Variables made with foreach)我得到了几个答案,我正在测试extract(),但出于安全原因,我看到了几个反对它。

现在我的问题是如何以安全的方式从$ _POST中使用提取,其中包含使用jquery序列化生成的数组。

安全意味着如果用户输入了错误的数据,安全的方式可以毫无问题地处理。

PHP站点在extract命令中有一个小警告,如下所示:

  

不要在不受信任的情况下使用extract()   数据,如用户输入(即$ _GET,   $ _FILES等)。例如,如果你这样做   如果你想运行旧的代码   依赖于register_globals   暂时,确保你使用其中一个   非重写extract_type   诸如EXTR_SKIP之类的值并且要注意   你应该提取相同的   订单的定义   php.ini中的variables_order。

它警告使用,但至少没有提供如何以安全的方式解决提取用户的例子。

6 个答案:

答案 0 :(得分:10)

最好的选择是根本不使用extract()。从用于编写安全代码的PHP相当于湿卫生纸的日子开始,这是一个糟糕的设计决定。

这可能会很痛苦,但写出一长串序列要好得多:

$var1 = $_POST['var1'];
$var2 = $_POST['var2'];
etc...

或者只是在代码中的任何地方使用$_POST['var1']和公司。

一旦开始使用数据提取,您就会为恶意用户提供一种潜在的代码方式,无论您投入多少时间/精力。你没有在银行金库门上钻一个洞,因为每次开门都要打开门太烦人了。一旦出现漏洞,它就会被利用。

答案 1 :(得分:7)

不要使用extract(),只需在POST / GET上使用foreach()来创建自己的数组/对象。 一旦你的代码开始变大,extract()将成为调试的噩梦。

答案 2 :(得分:6)

只要您使用其他变量中不存在的前缀,这就足够安全了:

extract($_POST, EXTR_PREFIX_ALL, 'unique_prefix');

提取物可能有危险的原因与使用register_globals相同。

答案 3 :(得分:1)

extract如果仅将其用于部分提取已知输入变量,则没有任何问题。这不是最好的语法,但可以用:

extract(array_intersect_key($_POST,
        array_flip(array("var1", "var2", "var3", "var4"))));

这减少了可能的$ _POST变量,并且不会提取意外的东西。一般的好处是你仍然可以使用array_map来应用一些过滤功能。在某些设置中,与单个变量复制相比,它可以减少代码混乱。

答案 4 :(得分:1)

使用简单的foreach而不是extract()是什么:

foreach($_POST as $k => $v) $$k = $v;

因此,您可以在$$k = $v;部分添加一些安全代码。

答案 5 :(得分:1)

在全局范围内使用提取物以及_REQUEST,_GET,_POST,_COOKIE是危险的。

但是,如果您只允许使用过滤机制使用的变量并取消设置来自外部的所有内容,则可以使用extract。

例如,如果你直接将_REQUEST,_GET,_POST,_COOKIE输入到一个函数中,该函数将在内部执行extract()并且只释放你在return()中定义的函数,那么你也是安全的。因为提取的其他内容 - 包括来自恶意企图的变量 - 将保留在功能范围内,并且无法执行任何操作。

因此,extract()尊重范围 - 您在函数内提取的任何内容都保留在该函数内部,您在类方法中提取的任何内容都保留在该类方法的范围内,并且在没有让它们出现的情况下不会出现在任何地方。

这意味着在全局范围和功能/对象范围内,您可以安全地将数据提取用于可信数据。

假设$ args是一个关联数组:


function funny($args)
{
  extract($args);

  // Hereon you can use the variables normally and they will stay in function scope

}

您的变量将保留在函数的范围内。

类方法相同:


class berserker
{
     public function funny($args)
     {
       extract($args);

       // Hereon you can use the variables normally and they will stay in method scope

     }

}