3

要旨

SQLインジェクションに対して脆弱になることなく、GET内の可変数のパラメーターに依存するSQLクエリを実行したいと思います。

パラメータ

私のURLは次のように形成できます:

https://www.example.com/index.php?param1=blah1,param2=blah2,param3=a,b,c

またはこのように:

https://www.example.com/index.php?param1=blah1,param2=blah2,param3=a,b,c,d,e,f,g

つまり、param3には、可変数のコンマ区切りパラメーターa、b、cなどを含めることができます。

ホワイトリスト

a、b、cなどのすべてのパラメーターを確認します。クエリを実行する前に、承認済みのホワイトリストに登録されています。

// $valid_params is an array of pre-approved parameters.
$arr = explode(',', clean($_GET['param3']));
$params = Array();
foreach($arr as $param){
  if(in_array($param, $valid_params)){
    array_push($params, $param);
  }
}

クエリ

私はデータベース接続を次のように設定しました(MySQLを使用):

$db_connection = new PDO("mysql:host={$DB_HOST};dbname={$DB_NAME}",$DB_USER,$DB_PASS);
$db_connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$db_connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

そして、私はこのようなクエリを実行したいと思います(安全を除いて):

$comma_separated_params = implode(',',$params);
$result = $db_connection->query("SELECT {$comma_separated_params} FROM some_table");

目標

私がこれを安全かつ効率的に行う方法を誰かが知っていますか?

4

5 に答える 5

1

オーバーヘッドに対する懸念に応じてSELECT *、PHP で配列をフィルター処理することができます。パラメーターがデータベースに送信されない場合は、インジェクションの余地がありません。

ただし、これは最もエレガントなソリューションではありません。これが私がそれを行う方法です:

$comma_separated_params =
  implode(
    ",",
    array_map(
      function($a) {return "`".$a."`";},
      array_intersect(
        explode(",",$_GET['param3']),
        $valid_params
      )
    )
  )
);

その1行の不思議(わかりやすくするために改行を追加)は、$_GET['param3']変数を取り、コンマで分割し、(ループの代わりに)有効なパラメーターと交差させ、foreach各要素をバッククォートでラップし(以下の注を参照)、最後にそれらを接着しますコンマと一緒。

バッククォートを使用すると、文字通り任意の文字列をフィールド名として使用できます。通常、名前としてキーワードを許可しますが、スペースを含む列名なども許可できます。$valid_paramsバッククォート内で意味を持つ唯一の文字は、バックスラッシュとバッククォートです。ここまで取得するには、リストに含まれている必要があるため、存在しないと想定しても安全です。

于 2012-09-05T18:04:19.587 に答える
0

これを完了するにはいくつかの作業が必要ですが、パラメーター バインディングを使用すると、次のようになります。

$binding = array();
$selects = array();
foreach ( $params as $value ) {
  $binding[] = ':' . $value; 
  $selects = '?';
}

$select = implode(',', $select);

$result = $db_connection->prepare("SELECT $select FROM some_table"); 
foreach ( $binding as $key => $bind ) {
  $result->bindParam($key, $bind, PDO::PARAM_STR);
}

$result->execute();
于 2012-09-05T18:11:01.083 に答える
0

ホワイトリストはここに行く方法です。すでに具体的に定義したもののみを許可する場合は、問題ありません。どれだけ効率的かというと、これはすべて相対的なものです。あなたが使用しているバージョンは、100 列未満のリストなど、比較的小さなリストでうまく機能するので、心配する必要はありません。

PDO を使用するためのボーナス ポイント。

「許可された」列の定義と実際にデータベースにあるものとが異なる可能性があります。よりリラックスした仕様はSHOW FIELDS、問題のテーブルを使用してフィールドを取得し、それらのみを許可することです。

于 2012-09-05T18:01:29.690 に答える
0

定義済みの値の特定のリストのみをパラメーター 3 で渡すことを許可しており、入力値をそれらと比較している場合、最終的に値を完全に制御できるため、注入の露出があるとは思いません。あなたの$comma_seperated_params変数に入ります。

于 2012-09-05T18:01:45.617 に答える
0

PDO::prepareが役に立ちます。これはまさに専門家が推奨しています。絶対に使用しないでくださいmysql_real_escape_string (string)。常に準備済みステートメントを使用してください。

于 2012-09-06T11:52:49.720 に答える