【问题标题】:Does PHP's DateTime class escape date from SQL injectionPHP 的 DateTime 类是否从 SQL 注入中转义日期
【发布时间】:2013-01-23 00:27:23
【问题描述】:

通常,我使用 PDO 的预处理语句、类型转换为 (int) 或 PDO::quote() 来防止 SQL 注入。对于此应用程序,我需要先使用 PHP 修改日期,然后再将其添加到查询中。我是否需要采取额外的措施来防止 SQL 注入,或者我是否安全?谢谢

$date = new DateTime($_GET['suspect_user_provided_date']);
$date->add(new DateInterval('P1D'));
$sql='SELECT * FROM table WHERE date<"'.$date->format('Y-m-d').'"';

【问题讨论】:

  • 假设 DateTime 构造函数没有安全漏洞,我会说你很好。
  • @lc。你还会做一个多余的 PDO::quote() 吗?
  • 请注意,从 PHP 5.3 开始,新的 DateTime($someUserValue) 可能会引发异常。 // 编辑:对 PDO::quote() 的调用不会是多余的,因为 DateTime 不会做任何事情来使您的值查询安全。但是,该值不包含任何恶意内容。
  • 老实说,我会像其他所有东西一样使用准备好的语句和参数,但也许只是我。在这种特殊情况下,它不应该有所作为。一旦它是一个DateTime 对象,你就不应该从中得到任何有趣的东西,如果用户数据很奇怪,则保存一个异常。
  • @DanielM。我可以处理的例外情况。注射我不能!

标签: php


【解决方案1】:

DateTime 对象是否安全并不重要。您应该转义传递给查询的数据,而不是依赖所提供库的安全性。如果您更改实现,则无需关心新实现是否安全。你应该总是逃避。否则,您将尝试回答 - 并记住 - 对于每个函数 - SQL 是否安全?对于 HTML?对于 CSV?对于 http / 邮件标头?因为……不要!发送查询的代码行应该对 DateTime 实现以及它是否安全一无所知

【讨论】:

  • +1。我在回答中试图说的更简洁的版本。
【解决方案2】:

这是一个很好的问题:PHP 日期格式化程序对 SQL 注入安全吗?

我想起点是格式是否按照您的示例进行了硬编码。日期格式字符串允许在格式化日期中包含原始字符,其中可能包含不安全的字符,因此如果您使用格式字符串的变量,那么答案肯定是不,它不安全。

如果您使用的是硬编码格式,就像您给出的示例一样,那么这是一个更难的问题,但归结为“DateTime::format 的输出是否会偏离所需的格式?”

对此的答案是可以——如果失败,它可以输出false。这不会破坏您的 SQL,但可能会给您带来意想不到的结果。

理论上,这应该是最糟糕的。

但是,您应该考虑防御性。没有什么可说的,在 DateTime 类中找不到一个微妙的错误,导致它输出格式错误的日期。通常,这种错误不会被视为安全问题;这只会令人烦恼。特别是在正常使用中难以复制的情况下。但结合将其直接传递给 SQL,很容易成为安全问题。

课程是防御性编程:清理一切。即使你确定它是安全的。不要假设您的语言或框架词不包含错误。防御性编程意味着在每个级别都安全,因此程序中或您无法控制的意外错误不会让您的代码容易受到攻击。

【讨论】:

  • 是的,Darhazer 的答案不太简洁,但信息量很大。
【解决方案3】:

DateTime 构造函数将解析参数并尝试将其设为日期。

如果不能,则返回 false(实际上从 PHP 5.3 开始抛出异常)。

这意味着您是安全的,因为 SQL 注入尝试用引号“欺骗”SQL 查询字符串,而 new DateTime 返回 DateTime 实例或 false(抛出异常)。但无论如何你都可以处理错误情况(从 PHP 5.3 开始)

try {
  $date = new DateTime($_GET['suspect_user_provided_date']);
}
catch (Exception $e) {
  echo "Error";
  exit;
}

$date->add(new DateInterval('P1D'));
$sql='SELECT * FROM table WHERE date<"'.$date->format('Y-m-d').'"';

【讨论】:

  • 不,它会从 PHP 5.3 开始抛出异常。
  • 编辑添加了 try / catch。谢谢
  • 我感觉很糟糕。你的回答是唯一回答这个问题的人。是的 DateTime 将阻止 SQL 注入。 Darhazer 的回答没有直接回答这个问题,但恰当地(在我看来)告诉你不要相信它。
  • 别难过。只需接受您认为更适合您的问题的答案,这将对其他读者有所帮助。
  • 是的,我做到了。你的答案是最好的直接答案,但我觉得其他人会更好地帮助未来的读者。感谢您的帮助!
【解决方案4】:

您发布的示例是安全的。但是为什么不使用准备好的语句呢?像这样:

     $pdo = new PDO($dsn, $user, $pass, $options = array (
        PDO::ATTR_ERRMODE,  PDO::ERRMODE_EXCEPTION
     ));

     $date = new DateTime($_GET['suspect_user_provided_date']);
     $date->add(new DateInterval('P1D'));

     $sql='
     SELECT
        * 
     FROM table 
     WHERE date < :dt';

     $stmt = $pdo->prepare($sql);
     $params = array (
        'dt' => $date->format('Y-m-d')
     );
     try {
         $res = $pdo->execute($params);
     } catch (PDOException $e) {
         echo $e->getMessage();
     }

【讨论】:

  • 我正在使用 PHP 来动态创建查询,它变得有点复杂。我展示的示例仅用于查询的一部分。也许我应该重新考虑。
  • 感谢 Hek2mgl。 +1 详细示例。但是,我了解如何使用准备好的语句。我的复杂性是由于查询的多个部分有时在其他查询之间共享,来自应用程序的不同部分,然后被组装和执行。
  • 嗯,听起来有点像有线设计。请注意,动态 SQL 生成(除了可能存在漏洞外)可能导致错误代码和调试噩梦
【解决方案5】:

当涉及到 SQL 时,通常最好不要考虑什么是安全的,什么是不安全的;只需使用准备好的语句来处理它:

$stmt = $db->prepare('SELECT * FROM table WHERE `date` < :now');
$stmt->execute(array(
    ':now' => $date->format('Y-m-d'),
));

【讨论】:

  • 我没有使用准备好的语句。这是我的主要观点。
  • @user1032531 在这种情况下,我的答案的第二部分更加突出:)
【解决方案6】:

取决于日期的输出格式。如果您要更改格式并将其输出一些文本(如当前语言环境中的月份或日期名称),则可能会导致不安全(或至少失败)查询,因为它可能包含一些引号。或者您可以出于某种原因自己加上引号。所以是的,不要怀疑并使用pdo-&gt;quote() 或更好的准备语句。

// safe
$date = new DateTime($_GET['suspect_user_provided_date']);
$date->add(new DateInterval('P1D'));
$sql='SELECT * FROM table WHERE date<"'.$date->format('Y-m-d').'"';

// failing
$date = new DateTime($_GET['suspect_user_provided_date']);
$date->add(new DateInterval('P1D'));
$sql='SELECT * FROM table WHERE date<"'.$date->format('\O\"\h\a\i \t\o\d\a\y \i\s Y-m-D').'"';

// not failing, whatever format you are using, using pdo::quote
$date = new DateTime($_GET['suspect_user_provided_date']);
$date->add(new DateInterval('P1D'));
$sql='SELECT * FROM table WHERE date<'.$dbh->quote($date->format('\O\"\h\a\i \t\o\d\a\y \i\s Y-m-D'));

// not failing, whatever format you are using, using prepared statments
$stmt = $dbh->prepare('SELECT * FROM table WHERE date < :date');
$date = new DateTime($_GET['suspect_user_provided_date']);
$date->add(new DateInterval('P1D'));
$stmt->bindValue(':date', $date->format('\O\"\h\a\i \t\o\d\a\y \i\s Y-m-D'), PDO::PARAM_STR);
$stmt->execute();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-14
    • 2015-10-27
    • 1970-01-01
    相关资源
    最近更新 更多