2012-08-10 191 views
3

PDO IST不是在目标系统我工作的支持,虽然我寻求防止使用PHP的5.1.xPostgres的-DB 8.2或以上版本 SQL注入的解决方案。目前有没有切换到PDO的机会。pg_prepare()预处理语句(不是PDO)是否阻止SQL注入?

我目前的解决方案是pg_prepare准备声明:

// 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的文档缺少有关的重要信息:

它讲述了 “以后使用”

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注入中的一个重要问题。程序员可以使用准备好的statemtents,但SQL注入缺乏可能仍然是错误的!
  • 除了Frank Heikens的回答,hoppa显示使用pg_prepare/pg_query_params防止SQL注入。不过谢谢。
  • 现在将使用与pg_query_params(感谢米伦A.拉德夫)
  • 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'); 
} 
+1

我应该这样认为,但您可以随时尝试查看':)'。注入您自己的'DROP TABLE'语句代替其中一个参数值,并查看是否可以让它删除一个虚拟表。 – halfer 2012-08-10 08:12:37

回答

6

准备好的语句对于SQL注入是安全的,因为没有人可以在准备好之后更改查询计划。但是,如果您的声明已经被入侵,您仍然遭受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"); 
} 
?> 
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库提供的。

+0

MySQL准备好的语句有一些令人讨厌的问题:如果准备好的语句具有给定的名称已经存在,则在准备好新语句之前隐式地释放它。这意味着如果新语句包含错误并且无法做好准备,则会返回错误并且不存在具有给定名称的语句。 – 2012-08-10 08:20:41

2

据我可以从文档中收集它应该防范你对SQL注入。

更通用的方法是使用pg_query_params,因为它没有连接准备查询。

1

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

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