L’instruction paramétrée peut-elle arrêter toute injection SQL?

Si oui, pourquoi y a-t-il encore autant d’injections SQL réussies? Tout simplement parce que certains développeurs sont trop stupides pour utiliser des instructions paramétrées?

Les liens que j’ai publiés dans mes commentaires à la question expliquent très bien le problème. J’ai résumé mes sentiments sur la raison pour laquelle le problème persiste, ci-dessous:

  1. Ceux qui débutent peuvent ne pas avoir connaissance de l’injection SQL.

  2. Certains sont au courant de l’injection SQL, mais pensent que l’échappement est la seule solution? Si vous effectuez une recherche rapide sur Google pour la php mysql query , la première page qui apparaît est la page mysql_query , sur laquelle il y a un exemple montrant l’interpolation des entrées utilisateur échappées dans une requête. Il n’y a aucune mention (du moins pas que je puisse voir) de l’utilisation d’instructions préparées à la place. Comme d’autres l’ont dit, il y a tellement de didacticiels qui utilisent l’interpolation des parameters, que ce n’est pas vraiment surprenant combien de fois il est utilisé.

  3. Un manque de compréhension du fonctionnement des instructions paramétrées. Certains pensent que ce n’est qu’un moyen sophistiqué d’échapper à des valeurs.

  4. D’autres sont au courant des instructions paramétrées, mais ne les utilisez pas car ils ont entendu dire qu’ils sont trop lents. Je soupçonne que beaucoup de personnes ont entendu à quel point les déclarations paramétrées sont incroyablement lentes, mais n’ont en fait pas effectué de test de leur propre chef. Comme Bill Karwin l’a souligné dans son exposé, la différence de performance devrait rarement être utilisée comme facteur lors de l’utilisation de déclarations préparées. Les avantages de préparer une fois, d’exécuter de nombreuses tâches semblent souvent avoir été oubliés, tout comme l’amélioration de la sécurité et de la maintenabilité du code.

  5. Certains utilisent des instructions paramétrées partout, mais avec une interpolation de valeurs non vérifiées telles que les noms de tables et de colonnes, les mots-clés et les opérateurs conditionnels. Les recherches dynamics, telles que celles qui permettent aux utilisateurs de spécifier un certain nombre de champs de recherche, conditions de comparaison et ordre de sorting différents, en sont des exemples.

  6. Fausse impression de sécurité lors de l’utilisation d’un ORM. Les ORM permettent toujours l’interpolation des parties d’instructions SQL – voir 5.

  7. La programmation est un sujet vaste et complexe, la gestion des bases de données est un sujet vaste et complexe, la sécurité étant un sujet vaste et complexe. Développer une application de firebase database sécurisée n’est pas facile – même les développeurs expérimentés peuvent être pris au dépourvu.

  8. La plupart des réponses sur stackoverflow ne sont pas utiles. Lorsque les utilisateurs écrivent des questions qui utilisent le SQL dynamic et l’interpolation de parameters, il manque souvent des réponses suggérant d’utiliser plutôt des instructions paramétrées. À quelques occasions, des personnes ont réfuté ma suggestion d’utiliser des déclarations préparées – généralement en raison de la surcharge de performances inacceptable perçue. Je doute sérieusement que ceux qui posent la plupart de ces questions se trouvent dans une situation où les quelques millisecondes supplémentaires nécessaires pour préparer une déclaration paramétrée auront un effet catastrophique sur leur application.

Lorsque des articles traitent de requêtes paramétrées stoppant les attaques SQL, ils n’expliquent pas vraiment pourquoi, il s’agit souvent de «ça marche, alors ne demandez pas pourquoi» – peut-être parce qu’ils ne se connaissent pas. Un signe certain d’un mauvais éducateur est celui qui ne peut pas admettre qu’ils ne savent rien. Mais je m’égare. Quand je dis que je trouve tout à fait compréhensible d’être confus, c’est simple. Imaginez une requête SQL dynamic

 sqlQuery='SELECT * FROM custTable WHERE User=' + Username + ' AND Pass=' + password 

donc une simple injection SQL serait juste pour mettre le nom d’utilisateur en tant que ‘OR 1 = 1– Cela rendrait effectivement la requête SQL:

 sqlQuery='SELECT * FROM custTable WHERE User='' OR 1=1-- ' AND PASS=' + password 

Cela signifie que sélectionner tous les clients où ils sont nom d’utilisateur est vide (”) ou 1 = 1, ce qui est un booléen, ce qui équivaut à vrai. Ensuite, il utilise – pour commenter le rest de la requête. Donc, cela va simplement imprimer toute la table client, ou faire ce que vous voulez, si vous vous connectez, il se connectera avec les privilèges du premier utilisateur, ce qui peut souvent être l’administrateur.

Maintenant, les requêtes paramétrées le font différemment, avec du code comme:

 sqlQuery='SELECT * FROM custTable WHERE User=? AND Pass=?' parameters.add("User", username) parameters.add("Pass", password) 

où nom d’utilisateur et mot de passe sont des variables pointant vers le nom d’utilisateur et le mot de passe associés

Maintenant, à ce stade, vous pensez peut-être, cela ne change rien du tout. Vous pouvez sûrement toujours mettre dans le champ nom d’utilisateur quelque chose comme Nobody OR 1 = 1 ‘, en faisant la requête:

 sqlQuery='SELECT * FROM custTable WHERE User=Nobody OR 1=1'-- AND Pass=?' 

Et cela semblerait être un argument valable. Mais vous auriez tort.

La manière dont les requêtes paramétrées fonctionnent est que sqlQuery est envoyé en tant que requête et que la firebase database sait exactement ce que cette requête va faire, et alors seulement, elle insérera le nom d’utilisateur et les mots de passe uniquement en tant que valeurs. Cela signifie qu’ils ne peuvent pas affecter la requête, car la firebase database sait déjà ce que la requête va faire. Donc, dans ce cas, il chercherait un nom d’utilisateur “Nobody OR 1 = 1 ‘-” et un mot de passe vide, qui devrait apparaître faux.

Ce n’est pas une solution complète cependant, et la validation des entrées devra encore être effectuée, car cela n’affectera pas les autres problèmes, tels que les attaques XSS, car vous pourriez toujours mettre JavaScript dans la firebase database. Ensuite, si cela est lu sur une page, il sera affiché comme un javascript normal, en fonction de toute validation de sortie. Donc, la meilleure chose à faire est d’utiliser la validation des entrées, mais d’utiliser des requêtes paramétrées ou des procédures stockées pour arrêter toute attaque SQL.

Eh bien bonne question. La réponse est plus stochastique que déterministe et je vais essayer d’expliquer mon sharepoint vue en utilisant un petit exemple.

Il y a beaucoup de références sur le net qui nous suggèrent d’utiliser des parameters dans nos requêtes ou d’utiliser la procédure stockée avec des parameters afin d’éviter l’injection SQL (SQLi). Je vais vous montrer que les procédures stockées (par exemple) ne sont pas le bâton magique contre SQLi. La responsabilité rest toujours sur le programmeur.

Considérez la procédure stockée SQL Server suivante qui obtiendra la ligne utilisateur d’une table “Utilisateurs”:

 create procedure getUser @name varchar(20) ,@pass varchar(20) as declare @sql as nvarchar(512) set @sql = 'select usrID, usrUName, usrFullName, usrRoleID '+ 'from Users '+ 'where usrUName = '''+@name+''' and usrPass = '''+@pass+'''' execute(@sql) 

Vous pouvez obtenir les résultats en passant comme parameters le nom d’utilisateur et le mot de passe. En supposant que le mot de passe soit en texte libre (pour simplifier cet exemple), un appel normal serait:

 DECLARE @RC int DECLARE @name varchar(20) DECLARE @pass varchar(20) EXECUTE @RC = [dbo].[getUser] @name = 'admin' ,@pass = '!@Th1siSTheP@ssw0rd!!' GO 

Mais ici nous avons une mauvaise technique de programmation utilisée par le programmeur dans la procédure stockée, donc un attaquant peut exécuter ce qui suit:

 DECLARE @RC int DECLARE @name varchar(20) DECLARE @pass varchar(20) EXECUTE @RC = [TestDB].[dbo].[getUser] @name = 'admin' ,@pass = 'any'' OR 1=1 --' GO 

Les parameters ci-dessus seront transmis comme arguments à la procédure stockée et la commande SQL qui sera exécutée sera:

 select usrID, usrUName, usrFullName, usrRoleID from Users where usrUName = 'admin' and usrPass = 'any' OR 1=1 --' 

..qui obtiendra toutes les lignes des utilisateurs

Le problème est que même si nous suivons le principe “Créer une procédure stockée et passer les champs à rechercher en tant que parameters”, le SQLi est toujours exécuté. C’est parce que nous venons de copier notre mauvaise pratique de programmation dans la procédure stockée. La solution au problème consiste à réécrire notre procédure stockée comme suit:

 alter procedure getUser @name varchar(20) ,@pass varchar(20) as select usrID, usrUName, usrFullName, usrRoleID from Users where usrUName = @name and usrPass = @pass 

Ce que j’essaie de dire, c’est que les développeurs doivent d’abord savoir ce qu’est une attaque SQLi et comment procéder, puis sauvegarder leur code en conséquence. Suivre aveuglément les «meilleures pratiques» n’est pas toujours le moyen le plus sûr… et c’est peut-être pour cette raison que nous avons tant de «meilleures pratiques» – échoue!

Oui, l’utilisation d’instructions préparées arrête toutes les injections SQL, au moins en théorie. En pratique, les instructions paramétrées ne sont peut-être pas de véritables instructions préparées, par exemple PDO en PHP les émule par défaut, il est donc ouvert à une attaque de casse .

Si vous utilisez de véritables déclarations préparées, tout est en sécurité. Eh bien, du moins tant que vous ne concaténez pas de code SQL non sécurisé dans votre requête en réaction à l’impossibilité de préparer des noms de table, par exemple.

Si oui, pourquoi y a-t-il encore autant d’injections SQL réussies? Tout simplement parce que certains développeurs sont trop stupides pour utiliser des instructions paramétrées?

Oui, l’éducation est le point principal ici, et les bases de code héritées. Beaucoup de didacticiels utilisent les échappements et ceux-ci ne peuvent pas être facilement supprimés du Web, malheureusement.

J’évite les absolus en programmation; il y a toujours une exception. Je recommande fortement les procédures stockées et les objects de commande. Une grande partie de mon arrière-plan est avec SQL Server, mais je joue avec MySql de temps en temps. Les procédures stockées, y compris les plans de requête mis en cache, présentent de nombreux avantages. Oui, cela peut être accompli avec des parameters et du SQL en ligne, mais cela ouvre davantage de possibilités pour les attaques par injection et ne permet pas de séparer les problèmes. Pour moi, il est également beaucoup plus facile de sécuriser une firebase database car mes applications n’ont généralement que des droits d’exécution pour lesdites procédures stockées. Sans access direct à la table / vue, il est beaucoup plus difficile d’injecter quoi que ce soit. Si l’utilisateur de l’application est compromis, il est uniquement autorisé à exécuter exactement ce qui a été prédéfini.

Mes deux centimes.

Je ne dirais pas “stupide”.

Je pense que les tutoriels sont le problème. La plupart des tutoriels SQL, des livres, peu importe ce qui explique le SQL avec des valeurs intégrées, ne mentionnant aucunement les parameters de liaison. Les personnes apprenant de ces tutoriels n’ont aucune chance de l’apprendre.

Étant donné que la plupart des codes ne sont pas écrits dans un souci de sécurité et de gestion, avec un choix entre l’ajout de fonctionnalités (en particulier des éléments visibles pouvant être vendus) et la sécurité / stabilité / fiabilité ancien. La sécurité n’est une préoccupation que lorsque cela devient un problème.

L’instruction paramétrée peut-elle arrêter toute injection SQL?

Oui, tant que votre pilote de firebase database offre un espace réservé pour chaque littéral SQL possible. La plupart des pilotes d’instructions préparés ne le font pas. Disons que vous ne trouverez jamais un espace réservé pour un nom de champ ou un tableau de valeurs. Ce qui fera qu’un développeur se tournera vers l’adaptation d’une requête à la main, en utilisant la concaténation et le formatage manuel. Avec résultat prévu.

C’est pourquoi j’ai créé mon wrapper Mysql pour PHP qui prend en charge la plupart des littéraux pouvant être ajoutés dynamicment à la requête, y compris les tableaux et les identificateurs.

Si oui, pourquoi y a-t-il encore autant d’injections SQL réussies? Tout simplement parce que certains développeurs sont trop stupides pour utiliser des instructions paramétrées?

Comme vous pouvez le voir, en réalité, il est impossible de paramétrer toutes vos requêtes, même si vous n’êtes pas stupide.

Tout d’abord, ma réponse à votre première question: Oui, à ma connaissance, en utilisant des requêtes paramétrées, les injections SQL ne seront plus possibles. En ce qui concerne vos questions suivantes, je ne suis pas sûr et ne peux que vous donner mon avis sur les raisons:

Je pense qu’il est plus facile de “simplement” écrire la chaîne de requête SQL en concaténant des parties différentes (peut-être même en fonction de certaines vérifications logiques) ainsi que les valeurs à insérer. Il suffit de créer la requête et de l’exécuter. Un autre avantage est que vous pouvez imprimer (écho, sortie ou autre) la chaîne de requête SQL, puis utiliser cette chaîne pour une requête manuelle sur le moteur de firebase database.

Lorsque vous travaillez avec des instructions préparées, vous avez toujours au moins une étape supplémentaire: vous devez créer votre requête (y compris les parameters, bien sûr). Vous devez préparer la requête sur le serveur. Vous devez lier les parameters aux valeurs réelles souhaitées. à utiliser pour votre requête Vous devez exécuter la requête.

C’est un peu plus de travail (et pas si simple à programmer) en particulier pour certains emplois “rapides et sales” qui se révèlent souvent très durables …

Meilleures salutations,

Boîte

Pour protéger votre application de l’injection SQL, procédez comme suit:

Étape 1. Contraindre l’entrée. Étape 2. Utilisez des parameters avec des procédures stockées. Étape 3. Utilisez des parameters avec SQL dynamic.

Reportez-vous à http://msdn.microsoft.com/en-us/library/ff648339.aspx

L’injection SQL est un sous-ensemble du problème plus important de l’injection de code, dans lequel les données et le code sont fournis sur le même canal et les données sont sockets pour du code. Les requêtes paramétrées empêchent que cela se produise en formant la requête en utilisant le contexte relatif aux données et au code.

Dans certains cas spécifiques, cela ne suffit pas. Dans de nombreux SGBD, il est possible d’exécuter dynamicment SQL avec des procédures stockées, en introduisant une faille d’injection SQL au niveau du SGBD. L’appel d’une telle procédure stockée à l’aide de requêtes paramétrées n’empêchera pas l’exploitation de l’injection SQL dans la procédure. Un autre exemple peut être vu dans cet article de blog .

Plus couramment, les développeurs utilisent la fonctionnalité de manière incorrecte. Habituellement, le code ressemble à ceci quand il est fait correctement:

 db.parameterize_query("select foo from bar where baz = '?'", user_input) 

Certains développeurs vont concaténer des chaînes et utiliser ensuite une requête paramétrée, ce qui ne crée pas la distinction de données / code susmentionnée qui fournit les garanties de sécurité recherchées:

 db.parameterize_query("select foo from bar where baz = '" + user_input + "'") 

L’utilisation correcte des requêtes paramétrées offre une protection très forte, mais pas impénétrable, contre les attaques par injection SQL.

Même si les instructions préparées sont correctement utilisées dans le propre code de l’application Web, des failles d’injection SQL peuvent toujours exister si les composants de code de firebase database construisent des requêtes à partir d’une entrée utilisateur de manière non sécurisée. Voici un exemple de procédure stockée vulnérable à l’injection SQL dans le paramètre @name:

 CREATE PROCEDURE show_current_orders (@name varchar(400) = NULL) AS DECLARE @sql nvarchar(4000) SELECT @sql = 'SELECT id_num, searchssortingng FROM searchorders WHERE ' + 'searchssortingng = ''' + @name + ''''; EXEC (@sql) GO 

Même si l’application transmet la valeur de nom fournie par l’utilisateur à la procédure stockée de manière sécurisée, la procédure elle-même la concatène directement en une requête dynamic et est donc vulnérable.