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

83

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 quelques recherches et 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 de procédures stockées dans PostgreSQL Core empêche-t-elle les attaques par injection SQL ou s'agit-il d'autre chose? Ou bien PostgreSQL est-il également sujet à l’injection SQL même si nous n’utilisons que des procédures stockées? Si oui, montrez-moi s'il vous plaît un exemple (par exemple livre, site, papier, etc.).

Am1rr3zA
la source
4
Bizarrement, les principales réponses ici sont principalement OT qui traite avec SQL Server, alors que la question concerne Postgres . Voici une réponse connexe pour Postgres: dba.stackexchange.com/questions/49699/… . Il y en a quelques autres, essayez une recherche: dba.stackexchange.com/…
Erwin Brandstetter
@ ErwinBrandstetter, la question initiale n'était pas étiquetée (par l'OP) avec postgres et était - et mentionne encore - plusieurs autres SGBD. Je suppose que c’est la raison pour laquelle les diverses réponses se sont concentrées sur d’autres SGBD. Je vous suggère d’en ajouter un de plus axé sur Postgres.
Ypercubeᵀᴹ
@ ypercubeᵀᴹ: Je vais ajouter une réponse ici quand je trouverai le temps. En attendant, j'ai mis à jour dba.stackexchange.com/questions/49699/… pour le rendre plus clair et complet.
Erwin Brandstetter

Réponses:

71

Non, les procédures stockées n'empêchent pas l'injection SQL. Voici un exemple réel (à partir d'une application interne créée par une personne créée là où je travaille) d'une procédure stockée qui permet malheureusement l'injection de code 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 à 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 souhaite, permettant ainsi une visite à partir de petites tables de Bobby .

Que vous utilisiez des instructions SQL ou des procédures stockées importait peu. L'important est de savoir si votre code 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.

Kyralessa
la source
46

Les attaques par injection SQL sont celles où des requêtes non approuvées sont directement ajoutées, ce qui permet à l'utilisateur d'exécuter efficacement du code arbitraire, comme l'illustre cette bande dessinée canonique XKCD.

Ainsi, nous obtenons la situation:

userInput = getFromHTML # "Robert ') Élève les étudiants de la table; -"

Query = "Sélectionnez * des étudiants où studentName =" + userInput

Les procédures stockées constituent, 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) se présentent comme suit:

 

créer Stored procdure foo (
sélectionnez * parmi les étudiants où studentName =: 1
)

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

Une procédure stockée n'est pas une défense magique contre SQL-Injection, car les utilisateurs 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 à percer si vous comprenez le fonctionnement de SQL-Injection.

Vous pouvez en savoir plus sur SQL-Injection:

Brian Ballsun-Stanton
la source
29

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

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

Une attaque par injection SQL consiste en une insertion ou une "injection" d'une requête SQL via les données d'entrée du client vers l'application. Un exploit réussi d’injection SQL peut lire des 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 dans le fichier de SGBD. système et, dans certains cas, émettre des commandes au 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'exécuter 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 Injection SQL. texte alternatif Je pense que vous avez compris le point :-)

Jetez un coup d’œil à la feuille de triche pour la prévention des injections SQL , les méthodes de prévention sont expliquées en détail ...

CoderHawk
la source
12

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 lors de la concaténation, mais ne sont pas "plus sûres" si vous utilisez, par exemple, du SQL dynamique.

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

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

Cela donne une syntaxe invalide, heureusement

En paramétrant 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'obtiendrez aucune ligne car je suppose que vous n'avez pas d'utilisateur x' AND 1=(SELECT COUNT(*) FROM Client); --

Si le processus stocké ressemblait à ceci (en utilisant du SQL dynamique concaténé ), votre appel de processus 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 l'ennemi principal de l'injection SQL

Les procédures stockées ajoutent encapsulation, traitement des transactions, autorisations réduites, etc., mais elles peuvent toujours être utilisées de manière abusive pour une injection SQL.

Vous pouvez consulter Stack Overflow pour en savoir plus sur le paramétrage.

gbn
la source
10

« Attaques par injection SQL se produisent lorsque l' entrée utilisateur est mal codé. En règle générale, l'entrée utilisateur est des données que l'utilisateur envoie avec sa requête, les valeurs -à- dire dans les $_GET, $_POST, $_COOKIE, $_REQUESTou des $_SERVERtableaux. Cependant, l' entrée utilisateur peut également provenir d'une variété d'autres sources, comme les sockets, les sites Web distants, les fichiers, etc. Par conséquent, vous devez vraiment traiter tout sauf les constantes (comme 'foobar') comme des entrées utilisateur . "

Récemment, j'ai étudié de manière approfondie ce sujet et j'aimerais partager avec d'autres du matériel très intéressant, rendant ainsi ce post plus complet et instructif pour tout le monde.



De YouTube


De Wikipedia


De l'OWASP


De PHP Manual


De Microsoft et Oracle


Débordement de pile


Scanner d'injection SQL

Ilia Rostovtsev
la source
2

Les procédures stockées n'empêchent pas, comme par magie, l'injection SQL, mais elles le facilitent grandement. 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 se pose que lors de la création d'une requête via la concaténation de chaînes (c-à-d. 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 assemblez des chaînes simplement pour définir l'entrée, vous le faites probablement mal. (Il existe des exceptions à cette règle. Une exception concerne la création de requêtes sur certaines bases de données. Vous risquez d'avoir des problèmes de performances si vous ne l'obligez pas à compiler une nouvelle requête à chaque exécution. Mais recherchez ce problème avant de vous lancer. )

Étape 2) Recherchez le moyen approprié 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 (espérons qu'aucun d'entre eux ne l'est encore, mais je ne serais pas surpris) - ou si vous devez toujours concaténer votre entrée (comme dans le cas "parfois" de requêtes de rapports comme J'ai fait allusion à ci-dessus), alors vous devez utiliser une fonction d'échappement appropriée. Ne l'écris pas toi-même. Par exemple, postgres fournit la fonction quote_literal (). Donc vous courriez:

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

De cette façon, si in_name est quelque chose de sournois comme '[snip] ou 1 = 1' (la partie "ou 1 = 1" signifie que toutes les lignes sont sélectionnées, permettant ainsi à l'utilisateur de voir les salaires qu'il ne devrait pas!), Puis quote_literal enregistre vos fesses par 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 bizarres.)

C'est l'essentiel! Permettez-moi maintenant de vous laisser avec un lien vers un article classique du gourou d'Oracle, Tom Kyte, sur le sujet de l'injection SQL, pour faire passer le message: Linky

MWDB
la source
N'oubliez pas de mentionner quote_ident()- mais en général, le moyen le plus simple d'écrire du SQL dynamique à l'épreuve des injections consiste à utiliser format()et utiliser les espaces réservés %Ipour les identificateurs et les %Llittéraux. De cette façon, le ||quote_....()
code