【问题标题】:How to securely create PHP variables with extract如何使用 extract 安全地创建 PHP 变量
【发布时间】:2011-08-26 19:05:33
【问题描述】:

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

现在我的问题是如何以安全的方式从 $_POST 中使用提取,该 $_POST 具有使用 jquery 序列化的数组。

安全的意思是如果用户输入了错误的数据,安全的方式可以毫无问题地解决这个问题。

PHP 站点在提取命令中有一个小警告,内容如下:

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

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

【问题讨论】:

  • 简单地使用 $_POST['key'] 或 $_GET['key'] 有什么问题?
  • 除了近 200 个变量外,什么都没有。但由于 Marc B 的回答,我认为我将不得不输入每一个。
  • 只是为了跟进 Marc B 的评论。大量变量是使用完整变量名的一个很好的理由。您可以立即在代码中的任何位置看到它的来源,并知道将其作为不安全的数据进行处理。

标签: php extract


【解决方案1】:

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

【讨论】:

  • Foreach?如果您不喜欢标准的 $_POST 数组,只需执行 $myVar = $_POST;。如果您从数组中获取一维,您将遇到与提取相同的漏洞问题。
【解决方案2】:

最好的选择是根本不使用extract()。从 PHP 在编写安全代码时就相当于湿厕纸的时代,这是一个糟糕的设计决策。

这可能会很痛苦,但最好写出一长串:

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

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

一旦您开始使用 extract,无论您投入多少时间/精力,恶意用户都可能会进入您的代码。您不会在银行金库门上钻孔,因为每次都必须打开门才能放出一些钱太烦人了。一旦有漏洞,就会被利用。

【讨论】:

  • 感谢您的历史。不知道。
【解决方案3】:

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

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

extract 可能危险的原因与使用register_globals 相同。

【讨论】:

  • 所以提取是安全的如果你使用一个唯一的前缀??
【解决方案4】:

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

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

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

【讨论】:

    【解决方案5】:

    用一个简单的 foreach 代替 extract() 怎么样:

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

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

    【讨论】:

    • 同样的安全问题,因为任何人都可以在浏览器中内联操作 post 数组的键和值。
    【解决方案6】:

    在全局范围内和 _REQUEST、_GET、_POST、_COOKIE 中使用提取是很危险的。

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

    例如,如果您直接将 _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
    
         }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-29
      相关资源
      最近更新 更多