7

通常,我使用 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').'"';
4

6 回答 6

9

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

于 2013-01-22T16:16:54.650 回答
2

构造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').'"';
于 2013-01-22T16:14:37.203 回答
2

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

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

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

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

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

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

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

于 2013-01-22T16:25:31.533 回答
1

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

     $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();
     }
于 2013-01-22T16:13:44.297 回答
1

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

$stmt = $db->prepare('SELECT * FROM table WHERE `date` < :now');
$stmt->execute(array(
    ':now' => $date->format('Y-m-d'),
));
于 2013-01-22T16:17:07.703 回答
0

取决于日期的输出格式。如果您要更改格式并将其输出一些文本(例如当前语言环境中的月份或日期名称),则可能会导致不安全(或至少失败)查询,因为它可能包含一些引号。或者您可以出于某种原因自己加上引号。所以是的,不要怀疑和使用pdo->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();
于 2013-01-22T16:27:23.427 回答