29

这个问题最初是在此处的评论中提出的。

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

这对我来说似乎没有必要,但我一直被告知要“过滤输入,转义输出”。那么,除了数据库(或其他形式的存储)之外,是否需要过滤输入的数据?

4

2 回答 2

34

好吧,会有不同的意见。

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

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

  2. filter扩展中有很多好东西。它可以节省您编写清理和验证代码的时间。当然,它并没有涵盖每一种情况,但已经足够让您可以更专注于特定的过滤/验证代码。

  3. 在调试/审核代码时使用该功能非常有用。使用该功能时,您确切知道输入将是什么。例如,如果您使用FILTER_SANITIZE_NUMBER_INT过滤器,那么您可以确定输入将是一个数字——没有 SQL 注入、没有 HTML 或 Javascript 代码等。另一方面,如果您使用类似的东西,FILTER_UNSAFE_RAW那么您就知道它应谨慎对待,而且很容易引起安全问题。

于 2013-02-27T03:14:50.027 回答
30

正如 Sverri M. Olsen 所说,对此有不同的看法。

我非常同意Filter Input, Escape Output的哲学。

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

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


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

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

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

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

我强烈不同意转义input。我已经遇到过过早转换数据是一个问题的现实世界情况。

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

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

[...] 输入时转义是错误的[...] 这是一个分层违规——它将输出格式问题混合到输入处理中。分层违规使您的代码更难理解和维护,因为您必须考虑其他层,而不是让每个组件和层各司其职。

默认情况下,您已损坏数据。系统 [...] 现在对输入的数据撒谎。

对输入进行转义不仅无法处理多个输出的问题,而且实际上会使您的数据对于许多输出不正确

PHP 曾经有一个称为魔术引号的功能。这是一个输入时转义功能,[...] 导致了各种问题。[...] 根据 Lerdorf 的说法,更新的 PHP 'filter' 扩展是“magic_quotes done right”。但它仍然受到这里描述的几乎所有问题的困扰。

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


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

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

术语

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

  1. 验证意味着确认对数据所做的任何假设,例如具有特定格式或具有值的必填字段
  2. to sanitize 意味着确认值完全符合预期(即 $id_num 应该只包含数字)

概括

一般来说(可能有一些例外),我建议如下:

  • 输入上使用验证过滤器
  • 输出上使用净化过滤器
  • 记住 TIMTOWDI - 例如,我更喜欢 htmlspecialchars()(有更多选项)而不是 FILTER_SANITIZE_FULL_SPECIAL_CHARS 或 FILTER_SANITIZE_SPECIAL_CHARS (转义换行符)
于 2013-12-04T20:31:37.610 回答