Des colonnes SQL paramétrées?
j'ai du code qui utilise des requêtes paramétrées pour empêcher l'injection, mais j'ai aussi besoin d'être capable de construire dynamiquement la requête indépendamment de la structure de la table. Quelle est la bonne façon de le faire?
voici un exemple, disons que j'ai une table avec le nom des colonnes, L'adresse, le téléphone. J'ai une page web où je run Afficher Les Colonnes et remplir un menu déroulant avec eux comme options.
ensuite, j'ai une boîte de texte appelée Recherche. Cette boîte de texte est utilisée comme paramètre.
Actuellement mon code ressemble à quelque chose comme ceci:
result = pquery('SELECT * FROM contacts WHERE `' + escape(column) + '`=?', search);
j'ai un pressentiment. La raison pour laquelle j'utilise des requêtes paramétrées est d'éviter d'utiliser escape. Aussi, escape n'est probablement pas conçu pour échapper aux noms de colonnes.
Comment puis-je m'assurer que cela fonctionne comme je l'entends?
Edit: La raison j'ai besoin de requêtes dynamiques c'est que le schéma est configurable par l'utilisateur, et je ne serai pas là pour réparer quoi que ce soit de codé.
6 réponses
au lieu de passer les noms de colonnes, passez simplement un identifiant que vous codez qui se traduira par un nom de colonne en utilisant une table hardcoded. Cela signifie que vous n'avez pas besoin de vous soucier des données malveillantes qui sont transmises, car toutes les données sont soit traduites légalement, soit connues pour être invalides. Code Psudoish:
@columns = qw/Name Address Telephone/;
if ($columns[$param]) {
$query = "select * from contacts where $columns[$param] = ?";
} else {
die "Invalid column!";
}
run_sql($query, $search);
Le truc est d'avoir confiance en vos routines d'évasion et de validation. J'utilise ma propre fonction SQL escape qui est surchargée pour les littérales de différents types. Nulle part je n'insère des expressions (par opposition à des valeurs littérales citées) directement à partir des entrées de l'utilisateur.
pourtant, cela peut être fait, je recommande une fonction séparée - et stricte - pour valider le nom de la colonne. Permettez-lui de n'accepter qu'un seul identifiant, quelque chose comme
/^\w[\w\d_]*$/
vous devrez compter sur suppositions que vous pouvez faire au sujet de vos propres noms de colonne.
j'utilise ADO.NET et l'utilisation de commandes SQL et SQLParameters à ces commandes qui prennent soin du problème D'évasion. Donc, si vous êtes dans un environnement Microsoft-tool aussi bien, je peux dire que je l'utilise avec beaucoup de succès pour construire dynamique SQL et pourtant protéger mes paramètres
bonne chance
faire la colonne basée sur les résultats d'une autre requête à une table qui énumère les valeurs de schéma possibles. Dans cette deuxième requête vous pouvez hardcode le select au nom de colonne qui est utilisé pour définir le schéma. si aucune ligne n'est retournée puis est entré colonne n'est pas valide.
en SQL standard,vous placez des identificateurs délimités entre guillemets. Cela signifie que:
SELECT * FROM "SomeTable" WHERE "SomeColumn" = ?
sélectionnera une table appelée SomeTable avec la majuscule affichée (pas une version cas convertie du nom), et appliquera une condition à une colonne appelée SomeColumn avec la majuscule affichée.
De lui-même, qui n'est pas très utile, mais...si vous pouvez appliquer la technique escape() avec des guillemets doubles aux noms entrés via votre formulaire web, alors vous pouvez construire votre requête raisonnablement en toute confiance.
bien sûr, vous avez dit que vous vouliez éviter d'utiliser escape - et en effet vous ne devez pas l'utiliser sur les paramètres où vous fournissez le ? lieu-titulaires. Mais où vous mettez les données fournies par l'utilisateur dans la requête, vous devez vous protéger contre les personnes malveillantes.
différents SGBD ont différentes façons de fournir des identificateurs délimités. MS SQL Server, par exemple, semble utiliser des crochets [SomeTable] au lieu de guillemet.
les noms de colonne dans certaines bases de données peuvent contenir des espaces, ce qui signifie que vous devez citer le nom de colonne, mais si votre base de données ne contient pas de telles colonnes, exécutez juste le nom de colonne par une expression régulière ou une sorte de contrôle avant d'épiler dans le SQL:
if ( $column !~ /^\w+$/ ) {
die "Bad column name [$column]";
}