web-dev-qa-db-fra.com

Quels sont les bons moyens d'empêcher l'injection SQL?

Je dois programmer un système de gestion des applications pour ma société OJT. Le front-end se fera en C # et le back-end en SQL.

Maintenant, je n'ai jamais fait de projet de cette envergure auparavant; à l'école, nous n'avions que des leçons de base sur SQL. D'une manière ou d'une autre, notre professeur a complètement échoué à discuter des injections SQL, quelque chose avec lequel je ne suis entré en contact qu'en lisant sur le net.

Donc de toute façon ma question est: comment empêcher les injections SQL en C #? Je pense vaguement que cela peut être fait en masquant correctement les champs de texte de l'application afin qu'il n'accepte que les entrées dans un format spécifié. Par exemple: une zone de texte d'e-mail doit être au format "[email protected]". Cette approche serait-elle suffisante? Ou .NET a-t-il des méthodes prédéfinies qui gèrent des trucs comme ça? Puis-je appliquer un filtre à une zone de texte afin qu'il n'accepte que le format d'adresse e-mail ou une zone de texte de nom afin qu'il n'accepte pas les caractères spéciaux?

36
LeonidasFett

En utilisant SqlCommand et son collection enfant de paramètres toute la douleur de la vérification de l'injection SQL vous est enlevée et sera gérée par ces classes.

Voici un exemple, tiré de l'un des articles ci-dessus:

private static void UpdateDemographics(Int32 customerID,
    string demoXml, string connectionString)
{
    // Update the demographics for a store, which is stored  
    // in an xml column.  
    string commandText = "UPDATE Sales.Store SET Demographics = @demographics "
        + "WHERE CustomerID = @ID;";

    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        SqlCommand command = new SqlCommand(commandText, connection);
        command.Parameters.Add("@ID", SqlDbType.Int);
        command.Parameters["@ID"].Value = customerID;

        // Use AddWithValue to assign Demographics. 
        // SQL Server will implicitly convert strings into XML.
        command.Parameters.AddWithValue("@demographics", demoXml);

        try
        {
            connection.Open();
            Int32 rowsAffected = command.ExecuteNonQuery();
            Console.WriteLine("RowsAffected: {0}", rowsAffected);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}
44
Oliver

Ma réponse est assez simple:

Utilisez Entity Framework pour la communication entre C # et votre base de données SQL. Cela rendra les chaînes SQL paramétrées qui ne sont pas vulnérables à l'injection SQL.

En prime, il est également très facile de travailler avec.

7
Øyvind Bråthen

L'injection SQL peut être un problème délicat, mais il existe des moyens de le contourner. Votre risque est réduit votre risque simplement en utilisant un ORM comme Linq2Entities, Linq2SQL, NHibrenate. Cependant, vous pouvez avoir des problèmes d'injection SQL même avec eux.

La chose principale avec l'injection SQL est l'entrée contrôlée par l'utilisateur (comme c'est le cas avec XSS). Dans l'exemple le plus simple, si vous avez un formulaire de connexion (j'espère que vous n'en avez jamais un qui fait cela) qui prend un nom d'utilisateur et un mot de passe.

SELECT * FROM Users WHERE Username = '" + username + "' AND password = '" + password + "'"

Si un utilisateur devait saisir ce qui suit pour le nom d'utilisateur Admin '- , l'instruction SQL ressemblerait à ceci lors de l'exécution sur la base de données.

SELECT * FROM Users WHERE Username = 'Admin' --' AND password = ''

Dans ce cas simple, l'utilisation d'une requête paramétrée (ce que fait un ORM) éliminerait votre risque. Vous avez également le problème d'un vecteur d'attaque d'injection SQL moins connu et c'est avec les procédures stockées. Dans ce cas, même si vous utilisez une requête paramétrée ou un ORM, vous aurez toujours un problème d'injection SQL. Les procédures stockées peuvent contenir des commandes d'exécution, et ces commandes elles-mêmes peuvent être suceptibles aux attaques par injection SQL.

CREATE PROCEDURE SP_GetLogin @username varchar(100), @password varchar(100) AS
DECLARE @sql nvarchar(4000)
SELECT @sql = ' SELECT * FROM users' +
              ' FROM Product Where username = ''' + @username + ''' AND password = '''+@password+''''

EXECUTE sp_executesql @sql

Cet exemple aurait donc le même problème d'injection SQL que le précédent même si vous utilisez des requêtes paramétrées ou un ORM. Et bien que l'exemple semble stupide, vous seriez surpris de la fréquence à laquelle quelque chose comme ça est écrit.

Mes recommandations seraient d'utiliser un ORM pour réduire immédiatement vos chances d'avoir un problème d'injection SQL, puis d'apprendre à repérer le code et les procédures stockées qui peuvent avoir le problème et à les résoudre. Je ne recommande pas d'utiliser ADO.NET (SqlClient, SqlCommand etc ...) à moins que vous ne le deviez, non pas parce qu'il n'est pas sûr de l'utiliser avec des paramètres mais parce qu'il est beaucoup plus facile de devenir paresseux et de commencer à écrire un SQL requête en utilisant des chaînes et en ignorant simplement les paramètres. Les ORMS font un excellent travail pour vous forcer à utiliser des paramètres parce que c'est exactement ce qu'ils font.

Ensuite, visitez le site OWASP sur l'injection SQL https://www.owasp.org/index.php/SQL_Injection et utilisez la feuille de triche pour l'injection SQL pour vous assurer que vous pouvez repérer et éliminer tous les problèmes qui surgir dans votre code. https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet enfin, je dirais de mettre en place un bon examen du code entre vous et les autres développeurs de votre entreprise où vous pouvez examiner le code de chacun comme l'injection SQL et XSS. Souvent, les programmeurs manquent ce genre de choses parce qu'ils essaient de précipiter certaines fonctionnalités et ne passent pas trop de temps à revoir leur code.

7
nerdybeardo

L'injection SQL ne doit pas être empêchée en essayant de valider votre entrée; à la place, cette entrée doit être correctement échappée avant d'être transmise à la base de données.

La façon d'échapper à l'entrée dépend totalement de la technologie que vous utilisez pour interfacer avec la base de données. Dans la plupart des cas et à moins que vous n'écriviez du SQL nu (que vous devriez éviter aussi fort que possible), le framework sera pris en charge automatiquement afin que vous bénéficiez d'une protection pare-balles gratuite.

Vous devriez approfondir cette question après avoir décidé exactement quelle sera votre technologie d'interface.

4
Jon