2012-08-10 48 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查詢中使用輸出。