pg_prepare()预处理语句(不是PDO)是否会阻止SQL注入?

时间:2012-08-10 07:55:00

标签: php security postgresql prepared-statement

目标系统不支持PDO我正在努力虽然我在上寻求使用 PHP 5.1.x 防止SQL注入的解决方案PostGres-DB 8.2 + 。目前没有机会切换到PDO。

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

// 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注入缺失可能仍然存在错误!
  • 除了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 个答案:

答案 0 :(得分: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");
}
?>

答案 1 :(得分: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也是如此,它是内置的language feature,而不是PHP库所提供的。

答案 2 :(得分:2)

就我从文档中收集而言,它应该防范SQL注入。

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

答案 3 :(得分:1)

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

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