【问题标题】:Does pg_prepare() prepared statement (not PDO) prevent SQL-Injection?pg_prepare() 准备好的语句(不是 PDO)是否防止 SQL 注入?
【发布时间】:2012-08-07 12:18:12
【问题描述】:

我正在处理的目标系统不支持 PDO,尽管我正在寻找一种解决方案来防止在 上使用 PHP 5.1.x 进行 SQL 注入PostGres-DB 8.2+。目前没有机会切换到 PDO。

我目前的解决方案是pg_prepare-prepared语句:

// Trying to prevent SQL-Injection
$query = 'SELECT * FROM user WHERE login=$1 and password=md5($2)';
$result = pg_prepare($dbconn, "", $query);
$result = pg_execute($dbconn, "", array($_POST["user"], $_POST["password"]));
if (pg_num_rows($result) < 1) {
  die ("failure");
}

但是 pg_prepare-documentation 缺少一个重要信息:

它讲述了“以后的使用”

pg_prepare() 创建一个准备好的语句以供以后执行 pg_execute() 或 pg_send_execute().[...]

它讲述了“命名/匿名声明”

该函数从 查询字符串,它必须包含单个 SQL 命令。 stmtname 可能是 "" 创建一个未命名的语句,在这种情况下,任何预先存在的 未命名的语句被自动替换;[...]

它讲述了“类型转换”

与 pg_prepare() 一起使用的准备好的语句也可以由 执行 SQL PREPARE 语句。 (但 pg_prepare() 更灵活 因为它不需要预先指定参数类型。)另外, 虽然没有用于删除准备好的语句的 PHP 函数, SQL DEALLOCATE 语句可用于此目的。

但它并不能说明这种预准备语句的实现是否可以避免 SQL 注入

*这个安全问题的几乎所有 cmets 都指的是 PDO 解决方案,其中在文档中注意到驱动程序可以防止 SQL 注入。但如果一个简单的解决方案可能是 pg_prepare,我现在会使用 pg_prepare。*

感谢您提供可能是最佳实践解决方案的重要信息。

编辑(标记为解决方案后): 感谢您提供非常有启发性的答案!

  • 我将 Frank Heikens 的解决方案标记为最佳答案,因为它解释了 SQL 注入中的一个重要点。程序员可能会使用准备好的语句,但 SQL-injection-lack 可能仍然存在错误!
  • 除了 Frank Heikens 的回答之外,hoppa 表明使用 pg_prepare/pg_query_params 可以防止 SQL 注入。不过谢谢。
  • 现在将使用带有 pg_query_params 的优化代码(感谢 Milen A. Radev)
  • 还有pg_escape_string() 作为替代方案(感谢halfer)

所有答案都有帮助:)

// Trying to prevent SQL-Injection (**updated**)
$sql_query = 'SELECT * FROM user WHERE login=$1 and password=md5($2);';
$result = pg_query_params($dbconn_login, $sql_query, array($_POST["user"], $_POST["password"]));
if (pg_num_rows($result) < 1) {
  die('failure');
}

【问题讨论】:

  • 我认为确实如此,但您可以随时尝试查看:)。注入您自己的DROP TABLE 语句来代替其中一个参数值,看看是否可以让它删除一个虚拟表。

标签: php security postgresql prepared-statement


【解决方案1】:

使用准备好的语句通常是最好的方法,因为您还应该从可以跳过的数据库优化中获得更好的 SQL 性能。

但是,了解其他的做事方式总是好的,因此请记住,您可以在受污染的变量上使用 pg_escape_string(),然后直接在 SQL 查询中使用输出。

【讨论】:

    【解决方案2】:

    准备好的语句不会受到 SQL 注入的影响,因为没有人可以更改查询计划准备好之后。但是,如果您的语句已经被泄露,您仍然会遭受 SQL 注入:

    <?php 
    // how NOT to construct your SQL....
    $query = 'SELECT * FROM user WHERE login=$1 and password=md5($2) LIMIT '. $_POST['limit']; -- injection!
    $result = pg_prepare($dbconn, "", $query);
    $result = pg_execute($dbconn, "", array($_POST["user"], $_POST["password"]));
    if (pg_num_rows($result) < 1) {
      die ("failure");
    }
    ?>
    

    【讨论】:

      【解决方案3】:

      据我从文档中收集到的信息,它应该可以防止 SQL 注入。

      更通用的方法是使用pg_query_params,因为它与准备查询无关。

      【讨论】:

        【解决方案4】:

        准备好的语句内置在 MySQL (http://dev.mysql.com/doc/refman/5.6/en/sql-syntax-prepared-statements.html) 中。注入预防机制也在 MySQL 中,请参阅之前链接页面中的引用:

        防止 SQL 注入攻击。参数值可以包含未转义的 SQL 引号和分隔符。

        PHP 库只是将它们的功能映射到 MySQL 函数(可能使用 http://docs.oracle.com/cd/E17952_01/refman-5.0-en/c-api-prepared-statement-function-overview.html)。所以是的,pg_prepare 也应该保护你的注入。

        [编辑] 我刚刚注意到您在谈论 PostgreSQL,对于 PostgreSQL 也是如此,它是内置的 language feature,而不是 PHP 库提供的东西。

        【讨论】:

        • MySQL 在预处理语句方面存在一些令人讨厌的问题:如果具有给定名称的预处理语句已经存在,则在新语句准备好之前它会被隐式释放。这意味着如果新语句包含错误并且无法准备,则会返回错误并且不存在具有给定名称的语句。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-01-05
        • 2011-05-01
        • 2017-07-05
        • 2011-08-02
        • 2018-02-21
        相关资源
        最近更新 更多