web-dev-qa-db-fra.com

Comment les requêtes paramétrées aident-elles contre l'injection SQL?

Dans les deux requêtes 1 et 2, le texte de la zone de texte est inséré dans la base de données. Quelle est la signification de la requête paramétrée ici?

  1. Passer txtTagNumber comme paramètre de requête

    SqlCommand cmd = new SqlCommand("INSERT INTO dbo.Cars " +"VALUES(@TagNbr);" , conn);
    cmd.Parameters.Add("@TagNbr", SqlDbType.Int);
    cmd.Parameters["@TagNbr"].Value = txtTagNumber.Text;
    
  2. Conversion de txtTagNumber en un entier avant de construire la requête

    int tagnumber = txtTagNumber.Text.ToInt16(); /* EDITED */
    INSERT into Cars values(tagnumber.Text); /* then is it the same? */
    

De plus, ici, j'utiliserais la validation des expressions régulières pour arrêter l'insertion de caractères illégaux.

49
sqlchild

Les requêtes paramétrées remplacent correctement les arguments avant d'exécuter la requête SQL. Il supprime complètement la possibilité d'une entrée "sale" modifiant la signification de votre requête. Autrement dit, si l'entrée contient du SQL, elle ne peut pas faire partie de ce qui est exécuté car le SQL n'est jamais injecté dans l'instruction résultante.

45
OJ.

l'injection sql se produit lorsqu'un paramètre possible contient sql et que les chaînes ne sont pas gérées comme il se doit

par exemple:

var sqlquerywithoutcommand = "select * from mytable where rowname =  '" + condition+''";

et la condition est une chaîne provenant de l'utilisateur dans la demande. Si la condition est malveillante, par exemple:

var sqlquerywithoutcommand = "select * from mytable where rowname =  '" + "a' ;drop table  mytable where '1=1"+"'";

vous pourriez finir par exécuter des scripts malveillants.

mais en utilisant des paramètres, l'entrée sera nettoyée de tout caractère pouvant échapper aux caractères de chaîne ...

vous pouvez être assuré, peu importe ce qu'il contient, qu'il ne pourra pas exécuter de scripts d'injection.

en utilisant l'objet de commande avec des paramètres le sql réellement exécuté ressemblerait à ceci

select * from mytable where rowname = 'a'';drop table mytable where 1=1'''

en essense, il recherchera une ligne avec rowname = a '; drop table mytable où 1 = 1' et n'exécutant pas le script restant

16
Mulki

Imaginez une requête SQL dynamique

sqlQuery='SELECT * FROM custTable WHERE User=' + Username + ' AND
Pass=' + password

donc une simple injection SQL serait juste de mettre le nom d'utilisateur en ' OR 1=1-- Cela rendrait effectivement la requête SQL:

sqlQuery='SELECT * FROM custTable WHERE User='' OR 1=1-- ' AND PASS='
+ password

Cela dit, sélectionnez tous les clients dont le nom d'utilisateur est vide ('') ou 1 = 1, qui est un booléen, ce qui équivaut à vrai. Ensuite, il utilise - pour commenter le reste de la requête. Ainsi, cela imprimera simplement toute la table client, ou fera tout ce que vous voulez avec, si vous vous connectez, il se connectera avec les privilèges du premier utilisateur, qui peut souvent être l'administrateur.

Maintenant, les requêtes paramétrées le font différemment, avec du code comme:

sqlQuery='SELECT * FROM custTable WHERE User=? AND Pass=?'

parameters.add ("Utilisateur", nom d'utilisateur) parameters.add ("Pass", mot de passe)

où nom d'utilisateur et mot de passe sont des variables pointant vers le nom d'utilisateur et le mot de passe entrés associés

Maintenant, à ce stade, vous pensez peut-être, cela ne change rien du tout. Vous pouvez sûrement toujours mettre dans le champ du nom d'utilisateur quelque chose comme Nobody OR 1 = 1 '-, ce qui rend la requête efficace:

sqlQuery='SELECT * FROM custTable WHERE User=Nobody OR 1=1'-- AND
Pass=?'

Et cela semblerait être un argument valable. Mais vous auriez tort.

Le fonctionnement des requêtes paramétrées est que la requête sqlQuery est envoyée en tant que requête et que la base de données sait exactement ce que fera cette requête, et alors seulement elle insérera le nom d'utilisateur et les mots de passe uniquement comme valeurs. Cela signifie qu'ils ne peuvent pas effectuer la requête, car la base de données sait déjà ce que fera la requête. Donc, dans ce cas, il recherchera un nom d'utilisateur de "Nobody OR 1=1'--" et un mot de passe vide, qui devrait apparaître faux.

Extrait de

10
user2156081

Les requêtes paramétrées gèrent tout - pourquoi se donner la peine?

Avec les requêtes paramétrées, en plus de l'injection générale, vous obtenez tous les types de données traités, les nombres (int et float), les chaînes (avec guillemets intégrés), les dates et les heures (pas de problèmes de formatage ou de localisation lorsque .ToString () n'est pas appelé avec la culture invariante et votre client passe à une machine avec un format de date inattendu).

2
Cade Roux

Il est tout à fait compréhensible pourquoi on se sentirait ainsi.

sqlQuery = "select * from users where username='+username+';"

contre

sqlQuery = "select * from users where username=@username;"

Les deux requêtes ci-dessus semblent faire la même chose, mais ce n'est pas le cas.

Le premier utilise une entrée pour une requête, le second décide de la requête mais ne substitue que les entrées telles qu'elles sont pendant l'exécution de la requête.

Pour être plus clair, les valeurs des paramètres sont situées quelque part sur la pile où la mémoire des variables est stockée et est utilisée pour la recherche en cas de besoin.

Donc, si nous devions donner ' OR '1'='1 comme entrée dans le nom d'utilisateur, le premier dynamiquement construira une nouvelle requête ou des requêtes dans le cadre de la chaîne de requête sql sqlQuery qui est ensuite exécuté.

Sur la même entrée, ce dernier rechercherait ' OR '1'=' dans le champ username de la table users avec la requête statique spécifiée dans la chaîne de requête sqlQuery

Juste pour le consolider, voici comment vous utilisez les paramètres pour faire une requête:

SqlCommand command = new SqlCommand(sqlQuery,yourSqlConnection);

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

command.Parameters.Add(parameter);
1
ant_1618

Les requêtes paramétrées permettent au client de transmettre les données séparément du texte de la requête. Où sur la plupart sans texte, vous feriez validation + échappement. Bien sûr, le paramétrage n'aide pas contre d'autres types d'injection, mais comme les paramètres sont passés séparément, ils ne sont pas utilisés comme requête de texte d'exécution.

Une bonne analogie serait le bit d'exécution "récent" utilisé avec la plupart des processeurs et systèmes d'exploitation modernes pour se protéger du débordement de tampon. Il permet toujours le débordement de la mémoire tampon mais empêche l'exécution des données injectées.

1
dvhh