web-dev-qa-db-fra.com

Les procédures stockées empêchent-elles l'injection SQL?

Est-il vrai que les procédures stockées empêchent les attaques par injection SQL contre les bases de données PostgreSQL? J'ai fait un peu de recherche et j'ai découvert que SQL Server, Oracle et MySQL ne sont pas sûrs contre l'injection SQL même si nous n'utilisons que des procédures stockées. Cependant, ce problème n'existe pas dans PostgreSQL.

L'implémentation des procédures stockées dans le noyau PostgreSQL empêche-t-elle les attaques par injection SQL ou s'agit-il d'autre chose? Ou PostgreSQL est-il également sensible à l'injection SQL même si nous n'utilisons que des procédures stockées? Dans l'affirmative, veuillez me montrer un exemple (par exemple, livre, site, papier, etc.).

84
Am1rr3zA

Non, les procédures stockées n'empêchent pas l'injection SQL. Voici un exemple réel (d'une application interne créée par quelqu'un où je travaille) d'une procédure stockée qui permet malheureusement l'injection SQL:

Ce code de serveur SQL:

CREATE PROCEDURE [dbo].[sp_colunmName2]   
    @columnName as nvarchar(30),
    @type as nvarchar(30), 
    @searchText as nvarchar(30)           
AS
BEGIN
    DECLARE @SQLStatement NVARCHAR(4000)
    BEGIN
        SELECT @SQLStatement = 'select * from Stations where ' 
            + @columnName + ' ' + @type + ' ' + '''' + @searchText + '''' 
        EXEC(@SQLStatement)
    END      
END
GO

à peu près équivalent aux postgres:

CREATE or replace FUNCTION public.sp_colunmName2 (
    columnName  varchar(30),
    type varchar(30), 
    searchText  varchar(30) ) RETURNS SETOF stations LANGUAGE plpgsql            
AS
$$
DECLARE SQLStatement VARCHAR(4000);
BEGIN
    SQLStatement = 'select * from Stations where ' 
            || columnName || ' ' || type || ' ' || ''''|| searchText || '''';
    RETURN QUERY EXECUTE  SQLStatement;
END
$$;

L'idée du développeur était de créer une procédure de recherche polyvalente, mais le résultat est que la clause WHERE peut contenir tout ce que l'utilisateur veut, permettant une visite de petites tables Bobby .

Que vous utilisiez des instructions SQL ou une procédure stockée n'a pas d'importance. L'important est de savoir si votre SQL utilise des paramètres ou des chaînes concaténées. Les paramètres empêchent l'injection SQL; les chaînes concaténées permettent l'injection SQL.

71
Kyralessa

Les attaques par injection SQL sont celles où les entrées non fiables sont directement ajoutées aux requêtes, permettant à l'utilisateur d'exécuter efficacement du code arbitraire, comme illustré dans cette bande dessinée canonique XKCD.

Ainsi, nous obtenons la situation:

 userInput = getFromHTML # "Robert ') Supprimer les étudiants de la table; -" 
 
 Requête = "Sélectionner * parmi les étudiants où studentName =" + userInput 

Les procédures stockées sont, en général, de bonnes défenses contre les attaques par injection SQL car les paramètres entrants ne sont jamais analysés.

Dans une procédure stockée, dans la plupart des bases de données (et des programmes, n'oubliez pas que les requêtes précompilées comptent comme des procédures stockées) ressemblent à ceci:

 
 
 créer Foo procdure stocké (
 sélectionnez * parmi les étudiants où studentName =: 1 
); 
 

Ensuite, lorsque le programme souhaite accéder, il appelle foo(userInput) et récupère joyeusement le résultat.

Une procédure stockée n'est pas une défense magique contre l'injection SQL, car les gens sont tout à fait capables d'écrire de mauvaises procédures stockées. Cependant, les requêtes précompilées, qu'elles soient stockées dans la base de données ou dans le programme, sont beaucoup plus difficiles à ouvrir des failles de sécurité dans si vous comprenez comment fonctionne SQL-Injection.

Vous pouvez en savoir plus sur SQL-Injection:

46

Oui, dans une certaine mesure.
Les procédures stockées seules n'empêcheront pas l'injection SQL.

Permettez-moi d'abord de citer l'injection SQL de OWASP

Une attaque par injection SQL consiste en l'insertion ou "l'injection" d'une requête SQL via les données d'entrée du client vers l'application. Un exploit d'injection SQL réussi peut lire les données sensibles de la base de données, modifier les données de la base de données (insérer/mettre à jour/supprimer), exécuter des opérations d'administration sur la base de données (telles que l'arrêt du SGBD), récupérer le contenu d'un fichier donné présent sur le fichier SGBD système et dans certains cas, émettre des commandes vers le système d'exploitation. Les attaques par injection SQL sont un type d'attaque par injection, dans lequel des commandes SQL sont injectées dans une entrée de plan de données afin d'effectuer l'exécution de commandes SQL prédéfinies.

Vous devez nettoyer les entrées utilisateur et ne pas concaténer les instructions SQL, même si vous utilisez une procédure stockée.

Jeff Attwood a expliqué les conséquences de la concaténation de sql dans " Donnez-moi le SQL paramétré, ou donnez-moi la mort "

Voici le dessin animé intéressant qui me vient à l'esprit chaque fois que j'entends SQL Injection alt text Je pense que vous avez compris :-)

Jetez un oeil à Aide-mémoire sur la prévention des injections SQL , les méthodes de prévention sont soigneusement expliquées ...

29
CoderHawk

La concaténation de chaînes est la cause de l'injection SQL. Ceci est évité en utilisant le paramétrage.

Les procédures stockées ajoutent une couche de sécurité supplémentaire en appliquant une syntaxe non valide lorsque vous concaténez, mais ne sont pas "plus sûres" si vous utilisez, par exemple, du SQL dynamique.

Donc, votre code ci-dessus est provoqué par concaténation de ces chaînes

  • exec sp_GetUser '
  • x' AND 1=(SELECT COUNT(*) FROM Client); --
  • ' , '
  • monkey
  • '

Cela donne une syntaxe invalide, heureusement

Paramétrer cela donnerait

exec sp_GetUser 'x'' AND 1=(SELECT COUNT(*) FROM Client); --' , 'monkey'

Ça signifie

  • @UserName = x' AND 1=(SELECT COUNT(*) FROM Client); --
  • @Password = monkey

Maintenant, dans le code ci-dessus, vous n'aurez aucune ligne parce que je suppose que vous n'avez pas d'utilisateur x' AND 1=(SELECT COUNT(*) FROM Client); --

Si le proc stocké ressemblait à ceci (en utilisant du SQL dynamique concaténé ), alors votre appel de proc stocké paramétré autorisera toujours l'injection SQL

...
SET @sql = 'SELECT userName from users where userName = ''' + 
               @UserName + 
               ''' and userPass = ''' +
               @Password +
               ''''
EXEC (@sql)
....

Ainsi, comme démontré, la concaténation de chaînes est le principal ennemi de l'injection SQL

Les procédures stockées ajoutent l'encapsulation, la gestion des transactions, des autorisations réduites, etc., mais elles peuvent toujours être utilisées abusivement pour l'injection SQL.

Vous pouvez regarder sur Stack Overflow pour en savoir plus sur paramétrage

12
gbn

"Les attaques par injection SQL se produisent lorsque entrée utilisateur n'est pas correctement codé. En général, l'entrée utilisateur correspond à des données que l'utilisateur envoie avec sa requête, c'est-à-dire des valeurs dans le $_GET, $_POST, $_COOKIE, $_REQUEST, ou $_SERVER tableaux. Cependant, les entrées des utilisateurs peuvent également provenir d'une variété d'autres sources, comme les sockets, les sites Web distants, les fichiers, etc. Par conséquent, vous devriez vraiment tout traiter sauf les constantes (comme 'foobar') comme entrée utilisateur . "

J'ai enquêté à fond sur ce sujet récemment et je voudrais partager avec d'autres personnes un matériel assez intéressant, rendant ainsi ce post plus complet et instructif pour tout le monde.



À partir de YouTube


De Wikipedia


Depuis OWASP


Depuis PHP Manual


De Microsoft et Oracle


Débordement de pile


Scanner d'injection SQL

10
Ilia Rostovtsev

Les procédures stockées n'empêchent pas comme par magie l'injection SQL, mais elles facilitent beaucoup la prévention. Tout ce que vous avez à faire est quelque chose comme ceci (exemple Postgres):

CREATE OR REPLACE FUNCTION my_func (
  IN in_user_id INT 
)
[snip]
  SELECT user_id, name, address FROM my_table WHERE user_id = in_user_id; --BAM! SQL INJECTION IMMUNE!!
[snip]

C'est ça! Le problème ne survient que lors de la formation d'une requête via la concaténation de chaînes (c'est-à-dire SQL dynamique), et même dans ces cas, vous pourrez peut-être lier! (Dépend de la base de données.)

Comment éviter l'injection SQL dans votre requête dynamique:

Étape 1) Demandez-vous si vous avez vraiment besoin d'une requête dynamique. Si vous collez des chaînes juste pour définir l'entrée, vous vous trompez probablement. (Il existe des exceptions à cette règle - une exception concerne le rapport des requêtes sur certaines bases de données, vous pouvez avoir des problèmes de performances si vous ne la forcez pas à compiler une nouvelle requête à chaque exécution. Mais recherchez ce problème avant de vous lancer dans cela. )

Étape 2) Recherchez la bonne façon de définir la variable pour votre SGBDR particulier. Par exemple, Oracle vous permet d'effectuer les opérations suivantes (en citant leurs documents):

sql_stmt := 'UPDATE employees SET salary = salary + :1 WHERE ' 
           || v_column || ' = :2';
EXECUTE IMMEDIATE sql_stmt USING amount, column_value; --INJECTION IMMUNE!!

Ici, vous ne concaténez toujours pas l'entrée. Vous vous engagez en toute sécurité! Hourra!

Si votre base de données ne prend pas en charge quelque chose comme ce qui précède (j'espère qu'aucun d'entre eux n'est toujours aussi mauvais, mais je ne serais pas surpris) - ou si vous devez vraiment concaténer votre entrée (comme dans le cas "parfois" de rapports de requêtes comme Je l'ai laissé entendre ci-dessus), alors vous devez utiliser une fonction d'échappement appropriée. Ne l'écrivez pas vous-même. Par exemple, postgres fournit la fonction quote_literal (). Vous courriez donc:

sql_stmt := 'SELECT salary FROM employees WHERE name = ' || quote_literal(in_name);

De cette façon, si in_name est quelque chose de détourné comme '[snip] ou 1 = 1' (la partie "ou 1 = 1" signifie sélectionner toutes les lignes, permettant à l'utilisateur de voir les salaires qu'il ne devrait pas!), Alors quote_literal enregistre vos fesses en faire la chaîne résultante:

SELECT salary FROM employees WHERE name = '[snip] or 1=1'

Aucun résultat ne sera trouvé (sauf si vous avez des employés avec des noms vraiment étranges.)

C'est l'essentiel! Maintenant, permettez-moi de vous laisser un lien vers un article classique du gourou d'Oracle Tom Kyte sur le sujet de l'injection SQL, pour ramener le clou: Linky

2
MWDB