【问题标题】:PHP's new input_filter does not read $_GET or $_POST arraysPHP 的新 input_filter 不读取 $_GET 或 $_POST 数组
【发布时间】:2010-09-22 20:22:16
【问题描述】:

在 PHP 5.2 中添加了一个很好的安全功能,称为“input_filter”,所以不要说:

$name = $_GET['name'];

你现在可以说:

$name = filter_input (INPUT_GET, 'name', FILTER_SANITIZE_STRING);

它会自动清理你的字符串,还有:

  • FILTER_SANITIZE_ENCODED
  • FILTER_SANITIZE_NUMBER_INT
  • FILTER_SANITIZE_EMAIL
  • FILTER_SANITIZE_URL

等等。 所以这是一个非常方便使用的安全功能,我想完全切换到它。

问题是……我经常在处理 $_GET 和 $_POST 数组之前对其进行操作,如下所示:

$_GET['name'] = '(默认名称)';

但 filter_input 似乎无法访问 $_GET 中的更改,因为它读取的是 int (?) 类型的“INPUT_GET”。如果我可以让 filter_input 改为读取 $_GET 那就太好了,但是:

$name = filter_input ( $_GET, 'name', FILTER_SANITIZE_STRING );

给我错误:

Warning: filter_input() expects parameter 1 to be long, array given.

谁能想到我能想到的方法:

  • 操纵INPUT_GET 的来源(无论它在哪里),以便我可以在 filter_input 读取它们之前更改它的值
  • 让 filter_input 读取$_GET

ADDENDUM:


Rich 问道:“你为什么要更改数组,当然你希望它们成为输入,而不是你以编程方式插入的东西。”

这只是一个非常方便的地方来预处理传入的变量,例如为了:

  • 设置默认值(如果 $_GET['state'] = '' 那么 $_GET['state'] = 'AL')
  • 进行手动处理(删除所有空格等)
  • 安全性(其中一些现在将由 filter_input 完成)

然后我知道当我得到传入变量时,它是安全有效的。当然,我可以将 $_GET 数组复制到另一个数组并处理那个数组,但这只是一个不必要的步骤,因为我 $_GET 已经是一个正常工作的数组,所以使用这些已经存在的系统数组来做是有意义的。

【问题讨论】:

    标签: php security filter-input


    【解决方案1】:

    按照 Jrngs 的建议:

    以编程方式跳过修改超全局请求变量并定义和使用新的普通变量。

    不仅创建新变量比访问和修改关联数组(带有字符串索引的数组)中的值要快得多,而且通常也是一种更好的做法。

    filter_input 函数的全部意义在于最终删除超全局变量的使用,因为它们是所有 PHP 脚本中最危险的一点,也是最常见的安全漏洞原因(对于 XSS 和SQL 注入)以及错误和混乱,尤其是在大型项目中。

    例如,$_GET 和 $_REQUEST 变量应该为同一个键返回相同的值,但是:

    .../?var=1
    var_dump($_GET['var']); ---> string '1' (length=1)
    var_dump($_REQUEST['var']); ---> string '1' (length=1)
    $_GET['var'] = 2;
    var_dump($_GET['var']); ---> int 2
    var_dump($_REQUEST['var']; ---> string '1' (length=1)
    

    更不用说超全局变量在面向对象的代码中几乎没有任何意义。

    因此,如果 filter_input 函数访问 $_GET/$_POST/$_REQUEST 超全局变量,那将完全违背该函数的意义。而且您绝对不应该为此使用建议的 filter_var 函数:

    filter_var($_GET['var'],FILTER_SANITIZE_STRING); ---> JUST NO!
    

    filter_var 函数的创建也是为了为非请求变量提供过滤/清理功能,而不是为这种“hack”。您所做的实际上是从 filter_input 函数中获取过滤器,该函数最初是为了提供对请求数据的更好和更安全的访问而创建的,完全绕过函数本身,以 的方式访问请求数据filter_input 被创建来替换和应用 filter_input 提供的过滤器在请求数据上。这是完全错误的。 :)

    【讨论】:

      【解决方案2】:

      PHP 的新 input_filter 不读取 $_GET$_POST 数组。 如果您要覆盖 Global 的(例如,$_GET,$_POST),那么不要使用 filter_input。 而是通过手动传递变量来使用filter_var ( $_GET['name'], FILTER_SANITIZE_STRING )

      【讨论】:

        【解决方案3】:

        无需修改全局数组即可轻松完成此操作:

        if (!($name = filter_input(INPUT_GET, 'name'))) {
            $name = 'default_value';
        }
        

        或者使用三元运算符:

        $name = ($name = filter_input(INPUT_GET, 'name')) ? $name : 'default_value';
        

        【讨论】:

          【解决方案4】:

          您可以使用filter_varfilter_var_array 手动强制它再次读取数组

          $name = filter_var ( $_GET['name'], FILTER_SANITIZE_STRING );
          

          【讨论】:

          • 好主意,但不幸的是“默认”选项不能与此一起使用。相反,您可以在变量名称之前添加一个 @ 符号(对于用户省略该参数的情况)。
          【解决方案5】:

          INPUT_GET 位只是一个标识符(数字),告诉 PHP 它需要从 $_GET 获取值。

          如果你想在整个数组上使用filter_input,你需要遍历它,将每个数组键发送到filter_input,然后将结果放回$_GET。

          编写一个对自己进行清理的函数可能同样容易,并且还应该允许您处理数组中的数组(看起来 filter_input 不会这样做)。 PHP.net 文档 cmets 中有几个这样的示例函数,它们可以执行诸如删除“魔术引号”之类的操作。示例见here

          【讨论】:

          • 这应该是正确的答案,因为它解释了需要做什么。由于同样的问题,我被带到这里:我没有使用 filter_input。对于其他任何人,如果您像这样使用它(假设您有 $_GET['foo']),它就可以工作: filter_input(INPUT_GET, 'foo', FLAGHERE);
          • 输入不是来自 $_GET 超全局变量。
          【解决方案6】:

          如果您手动更改阵列,您肯定不需要清理它吗?你为什么要改变数组,你肯定希望它们成为输入,而不是你以编程方式插入的东西。

          也许更多的代码/上下文会有所帮助。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2010-09-09
            • 1970-01-01
            • 1970-01-01
            • 2014-12-12
            • 2016-05-17
            • 1970-01-01
            • 2012-10-11
            相关资源
            最近更新 更多