何时使用filter_input()

时间:2013-02-27 01:48:53

标签: php security

此问题最初是在评论here中提出的。

如果您在打印任何用户提供的数据之前使用参数化查询和filter_input(),是否还需要htmlspecialchars()

我似乎没必要,但我总是被告知“过滤输入,逃避输出”。因此,除了数据库(或其他形式的存储)之外,是否还需要过滤输入的数据?

2 个答案:

答案 0 :(得分:30)

嗯,会有不同的意见。

我的看法是你应该总是使用它(或者,filter扩展名一般)。至少有三个原因:

  1. 您应该始终进行消毒输入。由于该功能为您提供了此功能,因此没有理由找到其他方法来消毒输入。由于它是一个扩展,过滤器也将比大多数PHP解决方案更快,更可能更安全,这当然不会受到伤害。唯一的例外是如果您需要更专业的过滤器。即使这样,您也应该使用FILTER_UNSAFE_RAW过滤器获取值(请参阅#3)。

  2. filter扩展程序中有很多好东西。它可以节省您编写清理和验证代码的时间。当然,它并不涵盖每一个案例,但足以让您更专注于特定的过滤/验证代码。

  3. 在调试/审核代码时,使用该函数非常有用。使用该功能时,您确切知道输入的内容。例如,如果您使用FILTER_SANITIZE_NUMBER_INT过滤器,那么您可以确定输入将是一个数字 - 没有SQL注入,没有HTML或Javascript代码等。另一方面,如果您使用类似的东西FILTER_UNSAFE_RAW然后您知道应该小心对待它,并且它很容易导致安全问题。

答案 1 :(得分:28)

正如Sverri M. Olsen所说,对此存在不同意见。

我非常同意哲学 过滤器输入,转义输出

  

如果在打印任何用户提供的数据之前使用参数化查询和htmlspecialchars(),是否还需要filter_input()?

简短回答: IMO,不是。这没有必要,但在某些情况下可能有用。


filter_input函数有许多有用的过滤器,我确实使用了其中的一些(即FILTER_VALIDATE_EMAIL)。 validate filters对于验证输入非常有用。但是,IMO,转换数据的那些只应在输出上使用。

有些人鼓励逃避投入。实际上,filter_input手册页上给出的示例似乎也鼓励了这一点。

$search_html = filter_input(INPUT_GET, 'search', FILTER_SANITIZE_SPECIAL_CHARS);
$search_url = filter_input(INPUT_GET, 'search', FILTER_SANITIZE_ENCODED);

唯一的例子是转义。结合函数名称(filter_ 输入)似乎表明转义输入是一种很好的做法。转义是必要的,但IMO应该在输出之前完成,而不是在输入之前完成。至少返回值存储在适当命名的变量中。

我强烈不同意转发输入 。我已经遇到过现实情况,过早转换数据是一个问题。

例如,Google Analytics处理输入的方式会导致我的编码&符号(%26)在排除查询参数之前被解码。结果是我的查询参数的统计信息实际上甚至不存在于我的URL中。有关此问题尚未解决,请参阅my question

您可能还想阅读Why escape-on-input is a bad idea。以下是我同意的一些摘录,以防文章消失[强调原文]。

  

[...]输入转义是错误的 [...]它是一种分层违规 - 它将输出格式问题混合到输入处理中。分层违规会使您的代码更难理解和维护,因为您必须考虑其他层而不是让每个组件和层执行自己的工作。

  

默认情况下,您的数据已损坏。该系统现在正在说明数据的来源。

  

转换输入不仅无法处理多个输出的问题,实际上会使许多输出的数据不正确

  

PHP曾经有一个名为魔术引号的功能。这是一个输入逃逸的功能,引起了各种各样的问题。 [...]根据Lerdorf的说法,更新的PHP'过滤器'扩展名是“magic_quotes right right”。但它仍然受到这里描述的几乎所有问题的困扰。

那么过滤器扩展如何比魔术引号更好(除了它有许多不同的过滤器之外)? 过滤器导致许多与魔术引号相同的问题。


以下是我使用的编码约定:

  • $ _POST,$ _GET,$ _REQUEST等中的值不应被转义,应始终被视为不安全
  • 值应在写入数据库或存储在$ _SESSION
  • 之前验证 1
  • 预期为数字或布尔值的值应在写入数据库或存储在$ _SESSION
  • 之前清理 2
  • 相信数据库和$ _SESSION中的数值和布尔值确实是数字或布尔值
  • 字符串值应该在直接用于任何SQL查询之前进行SQL转义(非字符串值应该被清理 2 )或使用预准备语句
  • 字符串值在用于HTML输出之前应进行HTML转义(非字符串值应清理 2
  • 字符串值在用于查询字符串之前应进行百分比编码(非字符串值应清理 2
  • 使用变量命名约定(例如* _url,* _html,* _sql)来存储转换后的数据

<强>术语

就我的目的而言,这是我定义上面使用的术语的方式。

  1. 验证意味着确认对数据做出的任何假设,例如具有特定格式或具有值的必填字段
  2. 清理意味着确认值正好符合预期(即$ id_num应该只包含数字)
  3. <强>摘要

    一般情况下(可能会有一些例外情况),我建议如下:

    • 输入
    • 上使用validate filters
    • 输出
    • 上使用sanitize filters
    • 记住TIMTOWDI - 例如,我更喜欢htmlspecialchars()(有更多选项)而不是FILTER_SANITIZE_FULL_SPECIAL_CHARS或FILTER_SANITIZE_SPECIAL_CHARS(逃脱换行符)