PHP: Handling (unexpected) arrays in user input
P粉547362845
P粉547362845 2024-04-01 17:56:37
0
1
468

I recently discovered that sending a variable containing an "unexpected" array (instead of a string) can cause fatal errors or other undesirable behavior. Example:

We have the following array:

$list = array(
"a" => "first",
"b" => "second"
);

The user sends $_REQUEST["key"], which will be used to find an element in the list:

echo ($list[$_REQUEST["key"]] ?? null);

If $_REQUEST["key"] is of type string, int, float, bool or null, the script will display the found entries or nothing (= null). This is the desired behavior.

If $_REQUEST["key"] is an array, the script will stop with a fatal error.


Now, the obvious solution is to add thousands of type checks (is_scalar() or !is_array()) throughout the code. But I'm wondering if the following alternatives sound reasonable from a security perspective:

At the beginning of each request, the following script will run:

$_COOKIE = array_map(function($e) { return (is_array($e) ? json_encode($e, JSON_INVALID_UTF8_IGNORE) : $e); }, $_COOKIE);
$_REQUEST = array_map(function($e) { return (is_array($e) ? json_encode($e, JSON_INVALID_UTF8_IGNORE) : $e); }, $_REQUEST);
$_POST = array_map(function($e) { return (is_array($e) ? json_encode($e, JSON_INVALID_UTF8_IGNORE) : $e); }, $_POST);
$_GET = array_map(function($e) { return (is_array($e) ? json_encode($e, JSON_INVALID_UTF8_IGNORE) : $e); }, $_GET);

This effectively disables sending the array to the server. If any positions in the code array are actually needed, they will be decoded manually using json_decode().

Is this a good idea?

P粉547362845
P粉547362845

reply all(1)
P粉668113768

You manually decode each input variable to avoid manually validating each input variable. To me, this is the same annoyance, but more confusing, with worse performance, and has new bugs (e.g. json_encode() will break if the input is not valid UTF-8) .

In general, it pays to be explicit about your application inputs. Making sure you use a set of known variables in a known state can really save time and trouble.

$key = isset($_REQUEST['key']) && is_string($_REQUEST['key']) ? $_REQUEST['key'] : null;
$item = $list[$key] ?? null;

If \TypeError is your only concern, you can wrap everything in a try/catch block.

You can use functions to avoid code duplication:

function get(string $name, ?string $default = null): ?string
{
    if (isset($_REQUEST[$name]) && is_string($_REQUEST[$name])) {
        return $_REQUEST[$name];
    }
    return $default;
}

You can build a validation framework or use a third-party framework.

I do a lot of things before messing with all the inputs, just to prevent specific corner cases.

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!