Question

J'ai un code qui utilise des requêtes paramétrées pour empêcher l'injection, mais je dois également pouvoir construire dynamiquement la requête, quelle que soit la structure de la table. Quelle est la bonne façon de faire cela?

Voici un exemple, disons que j’ai un tableau avec les colonnes Nom, Adresse, Téléphone. J'ai une page Web sur laquelle je lance Afficher les colonnes et que je remplis un menu déroulant de sélection avec ces options.

Ensuite, j'ai une zone de texte appelée Recherche . Ce champ de texte est utilisé comme paramètre.

Actuellement, mon code ressemble à ceci:

result = pquery('SELECT * FROM contacts WHERE `' + escape(column) + '`=?', search);

Cependant, je ressens un mauvais goût. J'utilise des requêtes paramétrées pour éviter d'utiliser échappement . De même, escape n'est probablement pas conçu pour échapper des noms de colonnes.

Comment puis-je m'assurer que cela fonctionne comme je le souhaite?

Modifier: La raison pour laquelle j'ai besoin de requêtes dynamiques est que le schéma est configurable par l'utilisateur, et je ne serai pas là pour réparer quoi que ce soit codé en dur.

Était-ce utile?

La solution

Au lieu de transmettre les noms de colonne, transmettez simplement un identifiant que votre code traduira en nom de colonne à l'aide d'une table codée en dur. Cela signifie que vous n'avez pas à vous soucier de la transmission de données malveillantes, 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);

Autres conseils

Le truc, c’est d’avoir confiance en vos routines d’évasion et de validation. J'utilise ma propre fonction d'échappement SQL surchargée pour des littéraux de types différents. Je n’insère nulle part des expressions (par opposition aux valeurs littérales citées) directement à partir de la saisie de l’utilisateur.

Néanmoins, cela peut être fait, je recommande une fonction distincte - et stricte - pour valider le nom de la colonne. Autorisez-le à n'accepter qu'un seul identifiant, comme

/^\w[\w\d_]*$/

Vous devrez vous appuyer sur des hypothèses que vous pouvez formuler concernant vos propres noms de colonne.

J'utilise ADO.NET et les commandes SQL et SQLParameters aux commandes qui traitent le problème Escape. Donc, si vous êtes également dans un environnement Microsoft-tool, je peux dire que je l’utilise très couramment pour construire du SQL dynamique tout en protégeant mes paramètres

bonne chance

Créez la colonne en fonction des résultats d'une autre requête dans une table énumérant les valeurs de schéma possibles. Dans cette seconde requête, vous pouvez coder en dur la sélection sur le nom de colonne utilisé pour définir le schéma. si aucune ligne n'est renvoyée, la colonne entrée est invalide.

En SQL standard, vous placez des identificateurs délimités entre guillemets. Cela signifie que:

SELECT * FROM "SomeTable" WHERE "SomeColumn" = ?

effectuera une sélection dans une table appelée SomeTable avec la capitalisation indiquée (il ne s'agit pas d'une version du nom convertie en majuscules), et appliquera une condition à une colonne appelée SomeColumn avec la capitalisation indiquée.

En soi, ce 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, vous pouvez alors construire votre requête avec une assurance raisonnable.

Bien sûr, vous avez dit que vous vouliez éviter l’utilisation de escape - et en effet vous n’avez pas à l’utiliser sur les paramètres où vous fournissez le? détenteurs de place. Mais lorsque vous placez des données fournies par l'utilisateur dans la requête, vous devez vous protéger des 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 guillemets doubles.

Dans certaines bases de données, les noms de colonne peuvent contenir des espaces, ce qui signifie que vous devez citer le nom de la colonne. Toutefois, si votre base de données ne contient aucune colonne de ce type, exécutez simplement le nom de la colonne avec une expression régulière ou une sorte de vérification avant de procéder à une épissure. le SQL:

if ( $column !~ /^\w+$/ ) {
  die "Bad column name [$column]";
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top