Domanda

È questo codice

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
   }
}

Iniezione sicura?

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

Posso legare un parametro a un'istruzione PDO come operatore di confronto?

È stato utile?

Soluzione

No, non puoi vincolare gli operatori in quel modo. Come soluzione alternativa, è possibile creare dinamicamente la query SQL "Base" e utilizzare una whitelist dell'operatore (che è abbastanza appropriato) per rimanere al sicuro dall'iniezione:

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;
}

A parte questo, il resto è multato e a prova di iniezione "per definizione".

Altri suggerimenti

A seconda del driver DBMS e PHP, le dichiarazioni preparate possono essere "reali" o emulate.

Nel primo caso, i parametri di bind vengono gestiti direttamente dal DBMS. In tal caso, la gestione di un operatore come parametro probabilmente attiverà un errore di sintassi. Il parser SQL analizzerà la query senza nemmeno guardare i parametri e non troverà un codice SQL valido su cui lavorare.

Nel secondo caso, i parametri di bind sono emulati dal driver: i valori di input vengono inseriti nel codice SQL (con adeguata fuga) e il DBMS riceve una query regolare completa. Non sono davvero sicuro di come si comporteranno gli attuali conducenti (avrei bisogno di testarlo) ma anche se non si lamentano di SQL non valido, colpiranno un muro prima o poi: gli operatori SQL non sono stringhe.

Ora, sarebbe una bella caratteristica essere implementata un giorno? Dubito che sia:

  • Non trarrai beneficio da SQL pre-paraloni quando si esegue query ripetitive: se si modificano gli operatori, si modifica la query.
  • Non otterrai sicuro Codice SQL. Come hai potuto?

Come accennato nel commento, non penso che sia possibile sfuggire all'operatore e farlo funzionare come ti aspetti. La query risultante sembrerebbe probabilmente qualcosa di simile:

'column' '=' 'value';

Non è necessario sfuggire all'operatore per evitare attacchi di iniezione, puoi convalidare l'operatore prima di aggiungerlo alla stringa, considera:

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");
    }
}

Puoi effettivamente farlo. L'SQL diventa più complicato. A seconda del numero di combinazioni, il SQL può diventare davvero enorme. Ma, a volte, quando ci sono solo poche scelte, è bello.

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'

Il valore potrebbe anche essere un'altra colonna, ma dovrai nidificare ancora un altro costrutto come la prima colonna e le combinazioni sono davvero impennate ora.

Comunque ... volevo solo dimostrare che si può fare.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top