Question

Est-ce ce code

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

Injection sûre?

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

Puis-je lier un paramètre à une instruction PDO comme opérateur de comparaison?

Était-ce utile?

La solution

Non, vous ne pouvez pas lier des opérateurs comme ça.Pour contourner ce problème, vous pouvez créer dynamiquement la requête SQL "de base" et utiliser une liste blanche d'opérateurs (ce qui est tout à fait approprié) pour rester à l'abri de l'injection:

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

En dehors de cela, le reste est parfait et résistant aux injections "par définition".

Autres conseils

En fonction du SGBD et du pilote PHP, les instructions préparées peuvent être "réelles" ou émulées.

Dans le premier cas, les paramètres de liaison sont gérés directement par le SGBD. Dans ce cas, la manipulation d'un opérateur en tant que paramètre déclenchera probablement une erreur de syntaxe. L'analyseur SQL analysera la requête sans même regarder les paramètres et ne trouvera pas de code SQL valide sur lequel travailler.

Dans le second cas, les paramètres de liaison sont émulés par le pilote: les valeurs d'entrée sont insérées dans le code SQL (avec un échappement adéquat) et le SGBD reçoit une requête régulière complète. Je ne suis pas vraiment sûr du comportement des pilotes actuels (je devrais le tester), mais même s'ils ne se plaignent pas d'un SQL invalide, ils toucheront un mur tôt ou tard: les opérateurs SQL ne sont pas des chaînes. / p>

Maintenant, serait-ce une fonctionnalité intéressante à mettre en œuvre un jour? J'en doute:

  • Vous ne bénéficierez pas du SQL pré-analysé lors de l'exécution de requêtes répétitives: si vous changez d'opérateur, vous modifiez la requête.
  • Vous n'obtiendrez pas de code SQL sûr . Comment pourriez-vous?

Comme mentionné dans le commentaire, je ne pense pas qu'il soit possible d'échapper à l'opérateur et de le faire fonctionner comme prévu.La requête résultante ressemblerait probablement à quelque chose comme:

'column' '=' 'value';

Vous n'avez pas besoin d'échapper à l'opérateur pour éviter les attaques par injection, vous pouvez valider votre opérateur avant de l'ajouter à la chaîne, considérez:

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

Vous pouvez réellement le faire.Le SQL devient juste plus compliqué.Selon le nombre de combinaisons, le SQL peut devenir vraiment énorme.Mais, parfois, quand il n'y a que quelques choix, c'est bien.

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'

La valeur: peut également être une autre colonne, mais vous devrez à nouveau imbriquer une autre construction de cas comme pour la première colonne, et les combinaisons sont vraiment en plein essor maintenant.

Quoi qu'il en soit ... je voulais juste montrer que cela pouvait être fait.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top