How to securely create PHP variables with extract

2019-01-19 12:14发布

问题:

In my previous post i ask how to create variables from an array ( PHP Variables made with foreach ) i got several answers and i was testing extract() but i have seen several against it for security reasons.

Now my question here is how can i use extract in a secure way from a $_POST that has an array that was made using jquery serialized.

With secure i mean that if a user inputs the wrong data, the secure way can take care of that with no problems.

THe PHP Site has a small warning in the extract command the says the following:

Do not use extract() on untrusted data, like user input (i.e. $_GET, $_FILES, etc.). If you do, for example if you want to run old code that relies on register_globals temporarily, make sure you use one of the non-overwriting extract_type values such as EXTR_SKIP and be aware that you should extract in the same order that's defined in variables_order within the php.ini.

It warns about the use but does not provide an example at least of how to solve the user of extract in a secure way.

回答1:

The best option is to not use extract() at all. It's a bad design decision from the days when PHP was the equivalent of wet toilet paper for writing secure code.

It may be painful, but it is far better to write out a long sequence of:

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

or simply use $_POST['var1'] and company everywhere in your code.

As soon as you start using extract, you're giving malicious users a potential way into your code, no matter how much time/effort you put into it. You don't drill a hole through a bank vault door because it's too annoying to have to open the door each time to let some money out. Once there's a hole, it will be exploited.



回答2:

Don't use extract(), just use foreach() on POST/GET to create your own array/object. extract() will be nightmare to debug once your code starts getting bigger.



回答3:

This is secure enough as long as you use a prefix that doesn't exist in other variables:

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

The reason why extract might be dangerous is the same as using register_globals.



回答4:

There is nothing wrong with extract if you only use it for partial extraction of known input variables. It's not the nicest syntax but doable with:

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

This cuts down on the possible $_POST variables and will not extract unexpected stuff. The general benefit is that you can still apply some filter function using array_map for example. In some settings it reduces code clutter in comparison to individual variable copying.



回答5:

What's about use a simple foreach instead extract():

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

So you can deal adding some security code on the $$k = $v; part.



回答6:

Its dangerous to use extract in global scope and for _REQUEST, _GET, _POST, _COOKIE.

However if you allow only the variables you are going to use by use of a filtering mechanism and unset everything that comes from outside, you can use extract.

For example, if you are directly feeding _REQUEST, _GET, _POST, _COOKIE into a function which will do the extract() inside and let out only the ones you define in return(), then you are safe too. Because whatever else is extracted - including variables from malicious attempts - will remain inside the function scope and wont be able to do anything.

So, extract() respects scope - anything you extract inside a function stays inside that function, anything you extract inside a class method stays in the scope of that class method and does not get out anywhere without you letting them.

Which means in global scope and in function/object scope you can safely use extract for trusted data.

Assuming that $args is an associative array :


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

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

}

Your variables will stay inside the scope of the function.

Same for a class method :


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

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

     }

}


标签: php extract