Partager via


Sécurisation des indications de code ADO.NET

Sécuriser votre application implique d'écrire du code sécurisé. Votre code ne doit exposer que les informations et les fonctionnalités requises par votre code client. Les attaques contre ADO.NET les plus fréquentes consistent à pénétrer dans SQL et à obtenir des informations de base de données confidentielles à partir d'exceptions retournées par une application.

Éviter les attaques par insertion dans SQL

L'insertion dans SQL se produit lorsqu'un agresseur ajoute des instructions SQL à vos commandes traitées au niveau de votre source de données. Ces commandes peuvent non seulement extraire des informations confidentielles, mais aussi modifier ou détruire des informations dans votre source de données. Dans le code vulnérable à ce type d'attaque, les chaînes de commande sont concaténées avec des entrées extérieures. Par exemple, le code suivant est vulnérable à une attaque par pénétration dans SQL.

' Retrieve CustomerID to search for from external source.
Dim custID As String = GetCustomerID()

' The following line of code allows for SQL Insertion attack.
Dim selectString As String = "SELECT * FROM Customers WHERE CustomerID = " & custID

Dim cmd As SqlCommand = New SqlCommand(selectString, conn)
conn.Open()
Dim myReader As SqlDataReader = cmd.ExecuteReader()
' Process results.
myReader.Close()
conn.Close()
[C#]
// Retrieve CustomerID to search for from external source.
string custID = GetCustomerID();

// The following line of code allows for SQL Insertion attack.
string selectString = "SELECT * FROM Customers WHERE CustomerID = " + custID;

SqlCommand cmd = new SqlCommand(selectString, conn);
conn.Open();
SqlDataReader myReader = cmd.ExecuteReader();
' Process results.
myReader.Close();
conn.Close();

Ici, l'agresseur s'attaquant à votre système peut entrer la valeur « 1;DROP TABLE Customers » pour l'IDClient demandé. En conséquence de quoi la commande suivante est exécutée pour la requête.

SELECT * FROM Customers WHERE CustomerID = 1;DROP TABLE Customers

Pour vous prémunir contre une attaque de ce type, validez les entrées provenant de sources extérieures et passez les valeurs de colonne en tant que paramètres au lieu de concaténer des valeurs pour créer une instruction SQL.

Validation des entrées

Il est possible d'utiliser des expressions régulières pour vérifier que les entrées correspondent à un format particulier. Le .NET Framework fournit l'objet Regex pour comparer une valeur à une expression régulière. Par exemple, le code suivant valide qu'un ID utilisateur est bien une chaîne alphanumérique de 5 caractères.

Public Static Function Validate(inString As String) As Boolean
  Dim r As Regex = New Regex("^[A-Za-z0-9]{5}$")
  Return r.IsMatch(inString)
End Function
[C#]
public static bool Validate(string inString)
{
  Regex r = new Regex("^[A-Za-z0-9]{5}$");
  return r.IsMatch(inString)
}

Utilisation de paramètres

Les paramètres constituent une méthode pratique d'organisation des valeurs passées avec une instruction SQL ou à une procédure stockée. En outre, les paramètres peuvent vous protéger contre une attaque par pénétration dans SQL, parce qu'ils garantissent que les valeurs reçues d'une source extérieure sont passées en tant que valeurs uniquement et non comme partie intégrante de l'instruction SQL. Par conséquent, les commandes SQL insérées dans une valeur ne sont pas exécutées à la source de données. Les valeurs passées sont au contraire traitées uniquement comme une valeur de paramètre. Le code suivant montre un exemple d'utilisation d'un paramètre pour le passage d'une valeur.

' Retrieve CustomerID to search for from external source.
Dim custID As String = GetCustomerID()

Dim selectString As String = "SELECT * FROM Customers WHERE CustomerID = @CustomerID"

Dim cmd As SqlCommand = New SqlCommand(selectString, conn)
cmd.Parameters.Add("@CustomerID", SqlDbType.VarChar, 5).Value = custID

conn.Open()
Dim myReader As SqlDataReader = cmd.ExecuteReader()
' Process results.
myReader.Close()
conn.Close()
[C#]
// Retrieve CustomerID to search for from external source.
string custID = GetCustomerID();

string selectString = "SELECT * FROM Customers WHERE CustomerID = @CustomerID";

SqlCommand cmd = new SqlCommand(selectString, conn);
cmd.Parameters.Add("@CustomerID", SqlDbType.VarChar, 5).Value = custID;

conn.Open();
SqlDataReader myReader = cmd.ExecuteReader();
' Process results.
myReader.Close();
conn.Close();

Protection de la confidentialité des informations d'exception

Il est fréquent que les agresseurs qui s'attaquent à votre système utilisent les informations contenues dans une exception (nom de votre serveur, d'une base de données ou d'une table, par exemple). Étant donné que les exceptions peuvent contenir des informations spécifiques à votre application ou votre source de données, vous pouvez protéger davantage celles-ci en n'exposant au client que les informations strictement nécessaires.

Pour éviter d'exposer des informations confidentielles dans les exceptions, ne retournez pas le contenu d'une exception système à l'utilisateur. Gérez plutôt l'exception en interne. Si un message doit être envoyé à l'utilisateur, retournez votre propre message personnalisé contenant des informations minimales (par exemple, « Échec de la connexion. Contactez votre administrateur système. ») et consignez dans un journal les informations spécifiques afin que l'administrateur puisse les exploiter.

Par exemple, le code suivant intercepte les exceptions lors de l'ouverture d'une connexion et les consigne dans le journal des événements.

Dim conn As SqlConnection = New SqlConnection("Data Source=localhost;Initial Catalog=Northwind;")

Try
  conn.Open()

Catch e As SqlException
  Dim log As System.Diagnostics.EventLog = New System.Diagnostics.EventLog()
  log.Source = "My Application"
  log.WriteEntry(e.ToString())

  If conn.State <> ConnectionState.Open Then _
    Console.WriteLine("Connection was not opened.")

Finally
  conn.Close()
End Try
[C#]
SqlConnection conn = new SqlConnection("Data Source=localhost;Initial Catalog=Northwind;");

try
{
  conn.Open();
}
catch (SqlException e)
{
  System.Diagnostics.EventLog log = new System.Diagnostics.EventLog();
  log.Source = "My Application";
  log.WriteEntry(e.ToString());

  if (conn.State != ConnectionState.Open)
    Console.WriteLine("Connection was not opened.");
}
finally
{
  conn.Close();
}

Voir aussi

Écriture de code ADO.NET sécurisé