搜索

首页  >  问答  >  正文

PHP:处理用户输入中的(意外)数组

我最近发现,发送包含“意外”数组(而不是字符串)的变量可能会导致致命错误或其他不良行为。示例:

我们有以下数组:

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

用户发送 $_REQUEST["key"],它将用于查找该列表中的某个元素:

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

如果 $_REQUEST["key"] 的类型为 stringintfloatboolnull,则脚本将显示找到的条目或不显示任何内容 (= null)。这就是所需的行为。

如果 $_REQUEST["key"]array,则脚本将因致命错误而停止。


现在,显而易见的解决方案是在整个代码中添加数千个类型检查(is_scalar()!is_array())。但我想知道从安全角度来看,以下替代方案听起来是否合理:

在每个请求开始时,以下脚本将运行:

$_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);

这实际上禁用了将数组发送到服务器的功能。如果实际需要代码数组中的任何位置,则将使用 json_decode() 手动解码它们。

这是个好主意吗?

P粉547362845P粉547362845276 天前600

全部回复(1)我来回复

  • P粉668113768

    P粉6681137682024-04-02 14:31:09

    您手动解码每个输入变量,以避免手动验证每个输入变量。对我来说,这也是同样的烦恼,但更令人困惑,性能较差,并且有新的错误(例如,如果输入不是有效的 UTF-8,json_encode() 将中断)。

    一般来说,明确您的应用程序输入是有好处的。确保您使用一组处于已知状态的已知变量确实可以节省时间和麻烦。

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

    如果 \TypeError 是您唯一关心的问题,您可以将所有内容包装在 try/catch 块中。

    您可以使用函数来避免代码重复:

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

    您可以构建验证框架或使用第三方框架。

    在弄乱所有输入之前,我会做很多事情,只是为了防止出现特定的极端情况。

    回复
    0
  • 取消回复