1

このコードは

class opinion
{
   private $dbh;
   var $opinionid,$opinion,$note,$actorid,$dateposted;
   var $isnew=FALSE;
   function loadby($column,$value,$operator="="){
       $dbh = new PDO(I deleted parameters here);
       $statement=$dbh->prepare("select * from fe_opinion where :column :operator :value");
       $statement->bindParam(":column", $column);
       $statement->bindParam(":value", $value);
       $statement->bindParam(":operator", $operator); //UNSURE, DOUBTFUL
       $statement->bindColumn("opinionid", $this->opinionid);
       $statement->bindColumn("opinion", $this->opinion);
       $statement->bindColumn("note", $this->note);
       $statement->bindColumn("actorid", $this->actorid);
       $statement->bindColumn("dateposted", $this->dateposted);
       $statement->fetch();
       return $statement->rowCount(); //please be 1
   }
}

注射は安全ですか?

       $statement->bindParam(":operator", $operator); //UNSURE, DOUBTFUL

比較演算子としてパラメーターをPDOステートメントにバインドできますか?

4

4 に答える 4

3

いいえ、そのような演算子をバインドすることはできません。回避策として、「ベース」SQLクエリを動的に作成し、演算子のホワイトリスト(これは非常に適切です)を使用して、インジェクションからの安全性を維持できます。

function loadby($column,$value,$operator="="){ 
   $dbh = new PDO(...); 
   $operator = getOperator($operator);
   if(!$operator) {
       // error handling
   }
   $statement=$dbh->prepare("select * from fe_opinion where :column $operator :value");
   // the rest like you already do it
} 

function getOperator($operator) {
   $allowed_ops = array('=', '<', '>'); // etc
   return in_array($operator, $allowed_ops) ? $operator : false;
}

これとは別に、残りは「定義上」問題なく注入防止です。

于 2011-12-05T18:25:33.663 に答える
0

コメントで述べたように、演算子をエスケープして期待どおりに機能させることは不可能だと思います。結果のクエリは、おそらく次のようになります。

'column' '=' 'value';

インジェクション攻撃を回避するために演算子をエスケープする必要はありません。文字列に追加する前に演算子を検証できます。次のことを考慮してください。

class opinion
{
    $validOperators = array('=', '>=', '>', '=<', '<');

    function loadby($column,$value,$operator="=") {

        // Validate operator
        if (!in_array($operator, self::$validOperators)) {
            throw new Exception('Invalid $operator ' . $operator . ')';
        }

        $statement=$dbh->prepare("select * from fe_opinion where :column " . $operator . " :value");
    }
}
于 2011-12-05T18:26:21.240 に答える
0

DBMSおよびPHPドライバーに応じて、プリペアドステートメントは「実際の」またはエミュレートされます。

最初のケースでは、バインドパラメータはDBMSによって直接処理されます。このような場合、演算子をパラメーターとして処理すると、構文エラーが発生する可能性があります。SQLパーサーは、パラメーターを見なくてもクエリを分析し、処理する有効なSQLコードを見つけられません。

2番目のケースでは、バインドパラメータがドライバによってエミュレートされます。入力値は(適切なエスケープを使用して)SQLコードに挿入され、DBMSは完全な通常のクエリを受け取ります。現在のドライバーがどのように動作するかはよくわかりませんが(テストする必要があります)、無効なSQLについて文句を言わなくても、遅かれ早かれ壁にぶつかります。SQL演算子は文字列ではありません。

さて、いつか実装されるのは素晴らしい機能でしょうか?私はそれがそうであるとは思わない:

  • 繰り返しクエリを実行する場合、事前に解析されたSQLのメリットはありません。演算子を変更すると、クエリが変更されます。
  • 安全なSQLコードを取得できません。なんてことするんですか?
于 2011-12-05T18:41:08.333 に答える
-2

あなたは実際にそれを行うことができます。SQLはさらに複雑になります。組み合わせの数によっては、SQLが非常に大きくなる可能性があります。しかし、選択肢が少ない場合は、それは素晴らしいことです。

select * 
  from someTable

where (case :column
       when 'age' then (case :operator
                               when '>' then age > :value
                               when '<' then age < :value
                        end)
       when 'price' then (case :operator
                               when '>' then price > :value
                               when '<' then price < :value
                        end)
      end)

  and someOtherCol = 'foo'

:valueも別の列である可能性がありますが、最初の列のようにさらに別のケース構造をネストする必要があり、組み合わせは現在非常に急増しています。

とにかく...それができることを示したかっただけです。

于 2011-12-05T19:13:04.187 に答える