Requêtes SQL standard avec concaténation de chaînes
Lors de la construction dynamique de requêtes SQL, une approche courante consiste à concaténer directement des valeurs dans la chaîne de requête. Pour les types non numériques, des guillemets simples sont ajoutés autour des valeurs.
Exemple avec concaténation directe :
int identifiant = 42;
string nomUtilisateur = "Marie";
string requete = "INSERT INTO Comptes VALUES(" + identifiant + ",'" + nomUtilisateur + "')";
Une autre méthode utilise des espaces réservés avec string.Format pour insérer les valeurs.
Exemple avec espaces réservés :
string template = "INSERT INTO Etudiants (Nom, Naissance, Age) VALUES('{0}', '{1}', {2})";
string requeteComplete = string.Format(template, "Dupont", "15-03-2000", 23);
Ces techniques de concaténation présentent des risques significatifs, notamment une vulnérabilité aux injections SQL, où des entrées malveillantes peuvent altérer le comportement de la requête.
Utilisation de requêtes paramétrées pour une sécurité renforcée
Pour prévenir les injections SQL, il est recommandé d'utiliser des requêtes paramétrées. Cela implique de définir des paramètres dans la requête SQL et de lier séparément les valeurs via l'objet SqlParameter.
Premier exemple avec paramètres individuels :
string chaineConnexion = "Server=localhost;Database=MaBase;User Id=admin;Password=secret;";
using (SqlConnection connexion = new SqlConnection(chaineConnexion))
{
connexion.Open();
string requeteSql = "INSERT INTO Utilisateurs (Identifiant, MotDePasse) VALUES (@id, @mdp)";
SqlCommand commande = new SqlCommand(requeteSql, connexion);
commande.Parameters.Add(new SqlParameter("@id", SqlDbType.NVarChar, 30)).Value = "jean_d";
commande.Parameters.Add(new SqlParameter("@mdp", SqlDbType.NVarChar, 30)).Value = "motDePasse123";
commande.ExecuteNonQuery();
}
Second exemple avec un tableau de paramètres :
string requeteSql = "INSERT INTO Produits (Reference, Designation, Prix) VALUES (@ref, @desc, @prix)";
SqlParameter[] parametres = new SqlParameter[]
{
new SqlParameter("@ref", "PROD-78901"),
new SqlParameter("@desc", "Clavier sans fil"),
new SqlParameter("@prix", 45.99m)
};
int lignesAffectees = ExecuterCommandeNonQuery(requeteSql, parametres);
Classe d'accès aux données générique
Une classe utilitaire peut encapsuler la logique de connexion et d'exécution des requêtes paramétrées.
public static int ExecuterCommandeNonQuery(string texteCommande, SqlParameter[] parametres = null)
{
using (SqlConnection cnx = new SqlConnection("MaChaineDeConnexion"))
{
using (SqlCommand cmd = new SqlCommand(texteCommande, cnx))
{
if (parametres != null)
{
cmd.Parameters.AddRange(parametres);
}
cnx.Open();
try
{
return cmd.ExecuteNonQuery();
}
catch (SqlException ex)
{
throw new Exception("Erreur lors de l'exécution de la commande : " + ex.Message);
}
}
}
}
Méthodes pour gérer les paramètres SqlParameter
La classe SqlParameter offre des méthodes pour ajouter des paramètres à une collection.
Ajout individuel avec Add :
SqlParameter paramNom = new SqlParameter("@nom", "Sophie");
commande.Parameters.Add(paramNom);
SqlParameter paramId = new SqlParameter("@idElement", 101);
commande.Parameters.Add(paramId);
Ajout groupé aveec AddRange :
SqlParameter[] ensembleParametres = new SqlParameter[]
{
new SqlParameter("@nom", "Lucas"),
new SqlParameter("@idElement", 202)
};
commande.Parameters.AddRange(ensembleParametres);