96 votes

Comment créer une requête SQL paramétrée? Pourquoi devrais-je?

J'ai entendu dire que "tout le monde" est paramétrée à l'aide de requêtes SQL pour les protéger contre les attaques par injection SQL sans avoir à vailidate chaque pièce de la saisie de l'utilisateur.

Comment faites-vous cela? Le faire automatiquement lors de l'utilisation de procédures stockées?

Donc, ma compréhension, c'est non paramétrée:

cmdText = String.Format("SELECT foo FROM bar WHERE baz = '{0}'", fuz)

Cela serait-il paramétrable?

cmdText = String.Format("EXEC foo_from_baz '{0}'", fuz)

Ou dois-je faire quelque chose de plus vaste comme ceci afin de me protéger contre l'injection SQL?

With command
    .Parameters.Count = 1
    .Parameters.Item(0).ParameterName = "@baz"
    .Parameters.Item(0).Value = fuz
End With

Existe-il d'autres avantages à utiliser des requêtes paramétrées outre les considérations de sécurité?

Mise à jour: Cet article a été lié à l'une des questions les références par Grotok. http://www.sommarskog.se/dynamic_sql.html

80voto

Joel Coehoorn Points 190579

Votre EXEC exemple ne serait PAS paramétrable. Vous avez besoin des requêtes paramétrées (déclarations préparées à l'avance dans certains cercles) pour empêcher l'entrée comme ceci de causer des dommages:

';DROP TABLE de bar;--

Essayez de le mettre dans votre fuz variable (ou pas, si vous la valeur de votre table de bar). De plus en plus subtiles, et d'endommager les requêtes sont possibles.

Voici un exemple de la façon dont vous faites les paramètres de Sql Server:

Public Function GetBarFooByBaz(ByVal Baz As String) As String
    Dim sql As String = "SELECT foo FROM bar WHERE baz= @Baz"

    Using cn As New SqlConnection("Your connection string here"), _
        cmd As New SqlCommand(sql, cn)

        cmd.Parameters.Add("@Baz", SqlDbType.VarChar, 50).Value = "Baz"
        Return cmd.ExecuteScalar().ToString()
    End Using
End Function

Les procédures stockées sont parfois crédité à la prévention de l'injection SQL. Cependant, la plupart du temps, vous avez encore de les appeler à l'aide des paramètres de requête ou ils n'aident pas. Si vous utilisez des procédures stockées exclusivement, alors vous pouvez désactiver les autorisations pour SÉLECTIONNER, mettre à JOUR, MODIFIER, CRÉER, SUPPRIMER, etc (à peu près tout, mais EXEC) pour l'application du compte d'utilisateur et d'obtenir une certaine protection de cette façon.

16voto

Tamas Czinege Points 49277

Certainement au second.

Les requêtes paramétrées, ont deux avantages principaux:

  • La sécurité: C'est une bonne façon d'éviter les Injection SQL vulnérabilités
  • Performance: Si vous régulièrement invoquer la même requête avec des paramètres d'une requête paramétrée peut permettre à la base de données de la mémoire cache de requêtes qui est une grande source de gain de performance.
  • Bonus: Vous n'aurez pas à vous soucier de la date et de l'heure de mise en forme des problèmes dans votre code de base de données. De même, si votre code sera exécuté sur des machines avec des paramètres régionaux non anglais, vous n'aurez pas de problèmes avec point décimal / décimal des virgules.

5voto

Andrew Hare Points 159332

Vous voulez aller avec votre dernier exemple car c'est le seul qui soit vraiment paramétré. Outre les problèmes de sécurité (qui sont beaucoup plus répandus que vous ne le pensez probablement), il est préférable de laisser ADO.NET gérer le paramétrage, car vous ne pouvez pas savoir avec certitude si la valeur que vous transmettez nécessite des guillemets simples ou non, sans inspecter les Type de chaque paramètre.

[Modifier] Voici un exemple:

 SqlCommand command = new SqlCommand(
    "select foo from bar where baz = @baz",
    yourSqlConnection
);

SqlParameter parameter = new SqlParameter();
parameter.ParameterName = "@baz";
parameter.Value = "xyz";

command.Parameters.Add(parameter);
 

2voto

JAL Points 11164

La plupart des gens le faire par le biais d'un langage de programmation côté serveur de la bibliothèque, comme PHP PDO ou Perl DBI.

Par exemple, dans PDO:

$dbh=pdo_connect(); //you need a connection function, returns a pdo db connection

$sql='insert into squip values(null,?,?)';

$statement=$dbh->prepare($sql);

$data=array('my user supplied data','more stuff');

$statement->execute($data);

if($statement->rowCount()==1){/*it worked*/}

Cela prend soin de s'échapper de vos données pour la base de données de l'insertion.

Un avantage est que vous pouvez répéter une insertion de nombreuses fois avec une déclaration préparée à l'avance, l'obtention d'un avantage de vitesse.

Par exemple, dans la requête ci-dessus, je pouvais préparer l'instruction une fois, puis une boucle sur la création du tableau de données à partir d'un tas de données et de répéter l' ->exécuter autant de fois que nécessaire.

1voto

Tony Andrews Points 67363

Votre texte de commande doit ressembler à:

 cmdText = "SELECT foo FROM bar WHERE baz = ?"

cmdText = "EXEC foo_from_baz ?"
 

Ajoutez ensuite des valeurs de paramètre. De cette façon, on s’assure que la valeur ne sera utilisée qu’en tant que valeur, alors que pour l’autre méthode, si la variable fuz est définie sur

 "x'; delete from foo where 'a' = 'a"
 

pouvez-vous voir ce qui pourrait arriver?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X