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 を使用します.*

おそらくベストプラクティスソリューションのこの重要な情報をありがとう。

編集(解決策としてマークされた後): 非常に啓発的な回答をありがとう!

  • SQL インジェクションの重要なポイントを説明しているため、Frank Heikens のソリューションを最良の回答としてマークしました。プログラマーは準備されたステートメントを使用する場合がありますが、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

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 に答える