2010-05-05 8 views
7

Mon idée est de créer des classes génériques pour Insert/Update/Select via une application C# (3.5) Winforms en train de parler avec une base de données MySQL via MySQL .NET Connector 6.2.2.Connecteur C# et MySQL .NET - Un moyen de prévenir les attaques SQL Injection dans une classe générique?

Par exemple:

public void Insert(string strSQL) 
{ 
    if (this.OpenConnection() == true) 
    { 
     MySqlCommand cmd = new MySqlCommand(strSQL, connection); 
     cmd.ExecuteNonQuery(); 
     this.CloseConnection(); 
    } 
} 

ensuite partout dans le programme que je peux exécuter une requête avec/sans entrée utilisateur en passant simplement une chaîne de requête SQL. Lecture autour de SO commence à me donner l'indication que cela peut conduire à des attaques par injection SQL (pour toutes les valeurs d'entrée de l'utilisateur)

Y a-t-il un moyen de nettoyer le strSQL entré ou dois-je créer des requêtes paramétrées individuelles dans chaque méthode qui doit faire une fonction de base de données?

Update1:

Ma solution finale ressemble à ceci:

public void Insert(string strSQL,string[,] parameterValue) 
{ 
    if (this.OpenConnection() == true) 
    { 
     MySqlCommand cmd = new MySqlCommand(strSQL, connection); 

     for(int i =0;i< (parameterValue.Length/2);i++) 
     {       
     cmd.Parameters.AddWithValue(parameterValue[i,0],parameterValue[i,1]);   
     } 

     cmd.ExecuteNonQuery(); 
     this.CloseConnection(); 
    }} 
+1

Cette idée crie horrible. Vous devez utiliser un ORM ou écrire des procs stockés. –

Répondre

9

Vous devriez certainement utiliser des requêtes paramétrées pour rester en sécurité.

Vous n'avez pas besoin de créer manuellement des requêtes paramétrées à chaque fois. Vous pouvez modifier la méthode générique que vous avez fourni à accepter une collection de MySqlParameters:

public void Insert(string strSQL, List<MySqlParameter> params) 
{ 
    if(this.OpenConnection() == true) 
    { 
     MySqlCommand cmd = new MySqlCommand(strSQL, connection) 
     foreach(MySqlParameter param in params) 
      cmd.Parameters.Add(param); 

     cmd.ExecuteNonQuery(); 
     this.CloseConnection(); 
    } 
} 

Je dois aussi mentionner que vous devriez être très prudent de nettoyer vos connexions après que vous avez fini de les utiliser (généralement dans un using manipulé bloc, mais je ne vois pas ce niveau de détail dans votre exemple de code).

+0

Merci Justin - Je commençais à penser à un moyen d'hybrider une classe générique avec des requêtes paramétrées mais vous me battez dessus. Pouvez-vous clarifier ce que vous entendez par bloc d'utilisation? –

+0

pouvez-vous m'apprendre comment je peux utiliser ce wrapper sql? merci =) –

1

Il est impossible de détecter l'injection SQL après le fait (autrement dit, une fois que vous avez construit une chaîne de requête dynamique , il est impossible de différencier ce qu'est le "vrai" SQL par rapport à tout SQL injecté).

Si votre intention est de permettre aux utilisateurs d'exécuter du SQL arbitraire, il semblerait que vous ne seriez pas trop inquiet à propos de l'injection SQL (puisque c'est le aim d'injection SQL).

+0

Merci @Adam - Je n'y avais pas pensé - je suppose qu'il pourrait y avoir quelques méthodes d'utilisation de Regex, etc. sur les requêtes mais chaque approche aurait probablement une vulnérabilité. –

+2

@John: Il n'y a pas de manière générique, RegEx ou non. Quelle que soit la méthode que vous utiliserez, vous devrez connaître * quelque chose * sur la façon dont la requête/l'instruction * devrait * apparaître, il n'y a donc aucun moyen de le faire de manière neutre. –

1

Je m'attendrais à ce qu'il soit assez difficile de nettoyer le texte brut qui sera utilisé pour SQL. Si possible, j'essaierais d'utiliser des opérations paramétrées. Une exception serait que vous n'exposiez pas la fonction publiquement et que vous n'ayez jamais transmis une chaîne construite à partir d'une entrée utilisateur brute.

1

Si vous utilisez MySqlParameter et ne générez pas de requêtes de chaîne de caractères simples, vous êtes en sécurité.

1

Vous ne pouvez pas vraiment faire cela - vous auriez besoin d'écrire un analyseur SQL qui est pour le moins non négligeable et sujettes aux erreurs.

Mordez la balle et paramétrez vos requêtes.

1

Je suggère d'utiliser des objets IDataParameter pour paramétrer vos requêtes.

10

La paramétrisation est très facile à faire. Beaucoup plus facile que de scruter les requêtes SQL, et moins de désordre ou d'erreur que l'échappement manuel.

modifié légèrement copier/coller à partir this tutorial page parce que je me sens paresseux:

// User input here 
Console.WriteLine("Enter a continent e.g. 'North America', 'Europe': "); 
string userInput = Console.ReadLine(); 

string sql = "SELECT Name, HeadOfState FROM Country WHERE [email protected]"; 
MySqlCommand cmd = new MySqlCommand(sql, conn); 
cmd.Parameters.AddWithValue("@Continent", userInput); 

using (MySqlDataReader dr = cmd.ExecuteReader()) 
{ 
    // etc. 
} 

Ce n'était pas si dur, était-il? :)

+0

Merci @Thorarin - Je suis allé avec la réponse @Justin Niessner en raison de sa nature générique (je ne veux pas de connexion/code MySQL dans toutes les méthodes) mais votre réponse aide définitivement à la syntaxe. –

+0

@John M: Vous êtes bienvenu à écrire des méthodes wrapper bien sûr. Mon but était de montrer le métal nu. – Thorarin

1

OUI vous avez besoin pour créer des requêtes paramétrées, tout va ailleurs d'introduire un risque d'injection SQL

+0

Je n'irais pas aussi loin. Il existe des moyens hermétiques d'échapper à l'entrée de l'utilisateur. Malheureusement les programmeurs sont seulement humains, et pourraient oublier d'échapper à quelque chose ... – Thorarin

+0

La question était de traiter/frotter après avoir été combiné avec SQL .... à ce stade est presque impossible à faire –