Mysql
 sql >> Base de données >  >> RDS >> Mysql

Puis-je utiliser une instruction préparée PDO pour lier un identifiant (un nom de table ou de champ) ou un mot clé de syntaxe ?

Puis-je utiliser une instruction préparée PDO pour lier un identifiant (un nom de table ou de champ) ou un mot clé de syntaxe ?

Malheureusement, une instruction préparée ne peut représenter qu'un littéral de données. Ainsi, un piège très courant est une requête comme celle-ci :

$opt = "id";
$sql = "SELECT :option FROM t WHERE id=?";
$stm  = $pdo->prepare($sql);
$stm->execute(array($opt));
$data = $stm->fetchAll();

Dépend des paramètres PDO, cette requête entraînera soit une erreur (en cas d'utilisation de véritables instructions préparées), soit simplement une chaîne littérale 'id' dans l'ensemble de champs (en cas de préparations émulées).

Ainsi, un développeur doit s'occuper lui-même des identifiants - PDO n'offre aucune aide pour cette affaire.

Pour sécuriser un identifiant dynamique, il faut suivre 2 règles strictes :

  • pour formater correctement l'identifiant
  • pour le vérifier par rapport à une liste blanche codée en dur .

Pour formater un identifiant, il faut appliquer ces 2 règles :

  • Entourez l'identifiant de backticks.
  • Évitez les backticks à l'intérieur en les doublant.

Après un tel formatage, il est prudent d'insérer la variable $table dans la requête. Ainsi, le code serait :

$field = "`".str_replace("`","``",$field)."`";
$sql   = "SELECT * FROM t ORDER BY $field";

Cependant, bien qu'un tel formatage soit suffisant pour les cas comme ORDER BY, pour la plupart des autres cas, il existe une possibilité pour un autre type d'injection :laisser un utilisateur choisir une table ou un champ qu'il peut voir, nous pouvons révéler certains des informations sensibles, comme un mot de passe ou d'autres données personnelles. Il est donc toujours préférable de vérifier les identifiants dynamiques par rapport à une liste de valeurs autorisées. Voici un bref exemple :

$allowed = array("name","price","qty");
$key     = array_search($_GET['field'], $allowed);
$field   = $allowed[$key];
$query   = "SELECT $field FROM t"; //value is safe

Pour les mots-clés, les règles sont les mêmes, mais bien sûr il n'y a pas de formatage disponible - ainsi, seule la liste blanche est possible et doit être utilisée :

$dir = $_GET['dir'] == 'DESC' ? 'DESC' : 'ASC'; 
$sql = "SELECT * FROM t ORDER BY field $dir"; //value is safe

Voir aussi cette note de contribution de l'utilisateur dans la documentation PHP :Note de l'utilisateur sur PDO ::quote