3

我正在研究的目标系统不支持 PDO,尽管我正在寻找一种解决方案来防止在 PostGres-DB 8.2+ 上使用PHP 5.1.x 进行SQL注入。目前没有机会切换到 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() 创建一个准备好的语句。[...]

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

该函数根据查询字符串创建一个名为 stmtname 的预准备语句,该语句必须包含一个 SQL 命令。stmtname 可以是 "" 来创建一个未命名的语句,在这种情况下,任何预先存在的未命名语句都会被自动替换;[...]

它讲述了“类型转换”

用于 pg_prepare() 的预处理语句也可以通过执行 SQL PREPARE 语句来创建。(但 pg_prepare() 更灵活,因为它不需要预先指定参数类型。)此外,虽然没有用于删除准备好的语句的 PHP 函数,但 SQL DEALLOCATE 语句可以用于此目的。

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

*此安全问题的几乎所有评论均指 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');
}
4

4 回答 4

6

准备好的语句不会受到 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");
}
?>
于 2012-08-10T08:25:22.190 回答
2

准备好的语句内置于 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 也是如此,它是一种内置语言功能,而不是 PHP 库提供的东西。

于 2012-08-10T08:00:54.610 回答
2

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

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

于 2012-08-10T08:11:52.437 回答
1

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

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

于 2012-08-10T08:15:23.143 回答