Les noms de table et de colonne NE PEUVENT PAS être remplacés par des paramètres dans PDO.
Dans ce cas, vous souhaiterez simplement filtrer et désinfecter les données manuellement. Pour cela, vous pouvez passer des paramètres abrégés à la fonction qui exécutera la requête de manière dynamique, puis utiliser une switch()
instruction pour créer une liste blanche de valeurs valides à utiliser pour le nom de la table ou le nom de la colonne. De cette façon, aucune entrée utilisateur ne va jamais directement dans la requête. Ainsi, par exemple:
function buildQuery( $get_var )
{
switch($get_var)
{
case 1:
$tbl = 'users';
break;
}
$sql = "SELECT * FROM $tbl";
}
En ne laissant aucun cas par défaut ou en utilisant un cas par défaut qui renvoie un message d'erreur, vous vous assurez que seules les valeurs que vous souhaitez utiliser sont utilisées.
array('u'=>'users', 't'=>'table', 'n'=>'nonsensitive_data')
etc.)default
. Si vous utilisez ce modèle, vous devez soit étiqueter l'un de voscase
s commedefault
, soit ajouter un cas d'erreur explicite tel quedefault: throw new InvalidArgumentException;
if ( in_array( $tbl, ['users','products',...] ) { $sql = "SELECT * FROM $tbl"; }
. Merci pour l'idée.mysql_real_escape_string()
. Peut-être qu'ici je peux le dire sans que quelqu'un se jette dedans et dise "Mais vous n'en avez pas besoin avec AOP"Pour comprendre pourquoi la liaison d'un nom de table (ou de colonne) ne fonctionne pas, vous devez comprendre comment fonctionnent les espaces réservés dans les instructions préparées: ils ne sont pas simplement substitués en tant que chaînes (correctement échappées) et le SQL résultant est exécuté. Au lieu de cela, un SGBD a demandé de "préparer" une instruction propose un plan de requête complet sur la façon dont il exécuterait cette requête, y compris les tables et les index qu'il utiliserait, qui seront les mêmes quelle que soit la façon dont vous remplissez les espaces réservés.
Le plan pour
SELECT name FROM my_table WHERE id = :value
sera le même que ce que vous remplacez:value
, maisSELECT name FROM :table WHERE id = :value
il ne peut pas être prévu d' apparence similaire , car le SGBD n'a aucune idée de la table à partir de laquelle vous allez réellement sélectionner.Ce n'est pas quelque chose qu'une bibliothèque d'abstraction comme PDO peut ou devrait contourner, car cela irait à l'encontre des 2 objectifs clés des instructions préparées: 1) pour permettre à la base de données de décider à l'avance de la manière dont une requête sera exécutée et d'utiliser la même chose planifier plusieurs fois; et 2) pour éviter les problèmes de sécurité en séparant la logique de la requête de l'entrée variable.
la source
TOP
/LIMIT
/OFFSET
, donc ce serait un peu déplacé en tant que fonctionnalité.Je vois que c'est un ancien message, mais je l'ai trouvé utile et j'ai pensé partager une solution similaire à ce que @kzqai a suggéré:
J'ai une fonction qui reçoit deux paramètres comme ...
À l'intérieur, je vérifie les tableaux que j'ai configurés pour m'assurer que seules les tables et les colonnes avec des tables "bénies" sont accessibles:
Ensuite, la vérification PHP avant d'exécuter PDO ressemble à ...
la source
$pdo->query($sql)
L'utilisation de la première n'est pas intrinsèquement plus sûre que la seconde, vous devez nettoyer l'entrée, qu'elle fasse partie d'un tableau de paramètres ou d'une simple variable. Donc, je ne vois rien de mal à utiliser ce dernier formulaire avec
$table
, à condition de vous assurer que le contenu de$table
est sûr (alphanum plus les traits de soulignement?) Avant de l'utiliser.la source
(Réponse tardive, consultez ma note complémentaire).
La même règle s'applique lors de la tentative de création d'une "base de données".
Vous ne pouvez pas utiliser une instruction préparée pour lier une base de données.
C'est à dire:
ne fonctionnera pas. Utilisez plutôt une liste de sécurité.
Note latérale: J'ai ajouté cette réponse (en tant que wiki communautaire) car elle sert souvent à fermer les questions avec, où certaines personnes ont posté des questions similaires à celles-ci en essayant de lier une base de données et non une table et / ou une colonne.
la source
Une partie de moi se demande si vous pourriez fournir votre propre fonction de nettoyage personnalisée aussi simple que celle-ci:
Je n'y ai pas vraiment réfléchi, mais il semble que supprimer quoi que ce soit, à l'exception des caractères et des traits de soulignement, pourrait fonctionner.
la source
MyLongTableName
il est facile de lire correctement, mais si vous vérifiez le nom stocké, il serait (probablement)MYLONGTABLENAME
qui n'est pas très lisible, doncMY_LONG_TABLE_NAME
est en fait plus lisible.Select * From $table
. Une liste blanche ou une correspondance de modèle stricte (par exemple, "noms commençant le rapport_ suivi de 1 à 3 chiffres uniquement") est vraiment essentielle ici.Quant à la question principale de ce fil, les autres articles ont expliqué pourquoi nous ne pouvons pas lier des valeurs aux noms de colonnes lors de la préparation des instructions, voici donc une solution:
Ce qui précède n'est qu'un exemple, donc inutile de dire que copier-> coller ne fonctionnera pas. Adaptez-vous à vos besoins. Maintenant, cela peut ne pas fournir une sécurité à 100%, mais cela permet un certain contrôle sur les noms de colonnes lorsqu'ils "entrent" en tant que chaînes dynamiques et peuvent être modifiés du côté des utilisateurs. En outre, il n'est pas nécessaire de créer un tableau avec les noms et types de colonnes de votre table car ils sont extraits du schéma information_schema.
la source