Question:
Injection SQL - pourquoi les guillemets d'échappement ne sont plus sûrs?
Incognito
2011-05-06 19:44:52 UTC
view on stackexchange narkive permalink

Raw SQL

Lorsque vous écrivez du SQL - pour tout ce qui nécessite vraiment une intervention humaine, beaucoup de choses ont été faites pour éviter l'injection.

Tous ceux qui sont entendus d'injection SQL sait que (je vais utiliser PHP comme exemple) faire quelque chose comme ça n'est pas sûr:

  $ sql = "SELECT * FROM ʻusers`. WHERE ʻuserName `=" {$ _POST ["username"]} ". AND` pass` = "{$ _POST [" pass "]}"; ";  

Magic

Ensuite, bien sûr, quelqu'un a eu l'idée d'utiliser des "guillemets magiques" pour traiter les entrées de programme qui n'étaient pas correctement nettoyées et directement placées dans SQL en raison de mauvaises pratiques. Cela n'a pas vraiment résolu le problème avec l'injection SQL, mais cela a signifié que toutes les entrées utilisateur ont été mutilées.

Ajout de barres obliques

Ainsi, certaines personnes ont désactivé les guillemets magiques. Ensuite, ils ont analysé l'entrée de l'utilisateur avant le point de SQL via ajoutelashes () qui en théorie échappe à toutes les citations et votre pirate ne peut pas faire 'OR 1 = 1 , mais même la documentation pour les addlashes dit que vous ne devriez pas utiliser les addlashes, elle dit utiliser la fonction spécifique à la base de données telle que mysql_real_escape_string () , mais cela est toujours dit que ce n'est pas suffisant par certains.

Ajout de barres obliques spécifiques à la base de données

Donc, nous ne pouvons pas utiliser * _real_escape_string spécifique au SGBD, nous ne pouvons pas utiliser ajouter des barres obliques , le truc des "citations magiques" a causé beaucoup de problèmes, et le Web regorge de citations courtes telles que:

"Un hacker dédié trouvera un moyen de sauter par-dessus votre citation boucles, utilisez simplement les instructions préparées par DBAL "- John Q n'importe quel programmeur

D'accord, cela m'a suffisamment effrayé pour utiliser des instructions prepare et un DBAL. Cela n'expliquait vraiment rien, mais cela sonne bien parce que je l'ai beaucoup entendu.

Instructions préparées

Nous utilisons maintenant PDO, ou un DBAL d'un framework, ou quelque chose d'autre qui encapsule tout notre SQL et s'assure que quelqu'un ne peut pas exécuter une injection SQL.

Ma question est essentiellement un "pourquoi pas?", pas un "que dois-je utiliser?". Le Web regorge de gens qui vous disent d'utiliser ceci ou d'utiliser cela ou quoi que ce soit , mais aucune explication sur les raisons pour lesquelles ces choses ont dû se produire.

Questions directes

Questions pointues (rappel, je pose des questions sur SQL, PHP était un exemple de langage à cause de sa mauvaise représentation autour de SQL, les concepts sont universels):

  1. Pourquoi ne pouvons-nous pas échapper à toutes les entrées utilisateur en utilisant "magic"?
  2. Pourquoi les addlashes n'étaient-ils pas "assez bons"?
  3. Quel est le problème avec l'utilisation des fonctions d'échappement spécifiques à la base de données, et pourquoi était-ce mieux que les addlashes?
  4. Pourquoi les instructions préparées avec des frameworks et PDO sont-elles saluées comme l'étalon-or de SQL? Pourquoi sont-ils meilleurs? Pourquoi ne puis-je pas faire une injection SQL avec ceux-ci, comme je pourrais le faire avec les moyens mentionnés précédemment? Un programmeur ne parvient-il pas en quelque sorte à tout gâcher? À quoi doivent-ils faire attention?
  5. Y a-t-il d'autres problèmes que je n'ai pas soulevés?
Sept réponses:
Hendrik Brummermann
2011-05-07 04:16:16 UTC
view on stackexchange narkive permalink

Pourquoi ne pouvons-nous pas échapper à toutes les entrées utilisateur en utilisant "magic"?

Au moment où la magie est appliquée, on ne sait pas où les données aboutiront. Ainsi, les guillemets magiques détruisent des données qui, à moins qu'elles ne soient écrites sans échappement dans une base de données.

Elles peuvent simplement être utilisées dans la réponse HTML renvoyée au client. Pensez à un formulaire qui n'a pas été complètement rempli et qui est donc montré à nouveau à l'utilisateur. Avec des guillemets magiques, les données saisies lors de la première tentative seront désormais échappées SQL, ce qui n'a aucun sens sur une page HTML. Pire encore: lors de la deuxième soumission, les données sont à nouveau échappées SQL.

Pourquoi les barres obliques ajoutées n'étaient-elles pas "assez bonnes"?

Il a des problèmes avec le multi-octet caractères:

  '27 \ 5c 뼧 bf 5c  

Ce sont deux octets, mais un seul caractère Unicode.

Depuis ajoutelashes ne sait rien sur Unicode, il convertit l'entrée bf 27 en bf 5c 27 . Si cela est lu par un programme compatible Unicode, il est vu comme 뼧 '. Boom.

Il y a une bonne explication de ce problème sur http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string

Quel est le problème avec l'utilisation des fonctions d'échappement spécifiques à la base de données, et pourquoi était-ce mieux que d'ajouter des barres obliques?

Ils sont meilleurs car ils garantissent que l'échappement interprète le données de la même manière que la base de données (voir la dernière question).

Du point de vue de la sécurité, ils sont acceptables si vous les utilisez pour chaque entrée de base de données. Mais ils courent le risque que vous les oubliez quelque part.

Modifier : comme l'a ajouté getahobby: Ou que vous utilisiez xxx_escape_strings pour les nombres sans ajouter de guillemets autour d'eux dans le SQL et sans garantir qu'il s'agit de nombres réels en transtypant ou en convertissant l'entrée dans le type de données approprié /Edit^

Du point de vue du développement logiciel, ils sont mauvais car ils rendent beaucoup plus difficile l'ajout de la prise en charge d'autres logiciels de serveur de base de données SQL.

Pourquoi les instructions préparées avec des frameworks et PDO sont-elles saluées comme le l'étalon-or de SQL? Pourquoi sont-ils meilleurs?

PDO est surtout une bonne chose pour des raisons de conception de logiciels. Cela facilite grandement la prise en charge d'autres logiciels de serveur de base de données. Il a une interface orientée objet qui résume la plupart des petites incompatibilités spécifiques à la base de données.

Pourquoi ne puis-je pas faire une injection SQL avec ces [instructions préparées], alors que je pourrais avoir avec le précédent mentionné signifie?

La partie " requête constante avec des paramètres variables " des instructions préparées est ce qui est important ici. Le pilote de la base de données échappera automatiquement à tous les paramètres sans que le développeur ait à y penser.

Les requêtes paramétrées sont souvent plus faciles à lire que les requêtes normales avec des paramètres échappés pour des raisons syntaxiques. Selon l'environnement, ils peuvent être un peu plus rapides.

Toujours utiliser des instructions préparées avec des paramètres peut être validé par les outils d'analyse de code statique . Un appel manquant à xxx_escape_string n'est pas repéré aussi facilement et de manière fiable.

Un programmeur ne parvient-il pas d'une manière ou d'une autre à tout gâcher? À quoi doivent-ils faire attention?

Les "instructions préparées" impliquent que les sont constantes . La génération dynamique d'instructions préparées - en particulier avec l'entrée de l'utilisateur - pose toujours tous les problèmes d'injection.

Ceci en profondeur et pas réaliste. 99,9% des applications Web ne sont pas concernées par les problèmes d'encodage de langue. ~ 0,1% de l'injection SQL est trouvée avec l'analyse de code statique. Il existe de bien meilleures techniques employées par les professionnels. Par expérience, je peux vous dire que les problèmes que j'ai traités sont ** beaucoup plus courants **.
Je ne suis pas d'accord avec @Rook, La réponse de Hendrik est bien réaliste. Le mantra PDO est généralement inutile car de nombreuses applications Web sont conçues pour utiliser une base de données spécifique jusqu'à leur fin de vie. Par conséquent, le développeur aurait tout aussi bien pu utiliser les fonctions pertinentes au lieu de trop compliquer une application pour utiliser 2% des fonctionnalités d'une extension.
Il n'y a que 4 ensembles de langues qui ont des problèmes avec `ajoutelashes ()`, gbk étant l'un d'entre eux.
@Rook - encore une fois, vous recourez à des insultes plutôt que de répondre à des questions. Ceci est inacceptable. Vous devez soit régler votre style de communication et votre comportement, soit nous devrons recourir à la suspension. Veuillez prendre cela comme un avertissement poli.
En ce qui concerne la dernière question "Un programmeur ne parvient-il pas d'une manière ou d'une autre à tout foutre en l'air?", Je voulais juste faire un lien vers un [problème d'injection SQL récent] (http://drupal.stackexchange.com/questions/133795/what-kind -of-attack-does-the-patch-for-sa-core-2014-005-drupal-7-32-prevent) qui ont affecté le contenu Drupal CMS, en contournant la protection PDO.
Christian
2011-05-08 12:45:57 UTC
view on stackexchange narkive permalink

[1.] Pourquoi ne pouvons-nous pas échapper à toutes les entrées utilisateur en utilisant "magic"?

Parce que les guillemets magiques sont brisés à deux titres:

  1. Toutes les données $ _ (REQUEST / GET / POST) ne vont pas dans la base de données. Et pour que vous en donniez un sens, vous devez supprimer l'entrée.
  2. Ce sont les addlashes équivalents (voir ma note sur [2.]), par conséquent, ils ne sont pas réellement sécurisés.

[2.] Pourquoi les ajouts-obliques n'étaient-ils pas "assez bons"?

Il y en a beaucoup moyens de sortir de la restriction ajoutelashes , par conséquent, c'est fondamentalement défectueux, quelle que soit la façon dont vous essayez de l'utiliser.

[3.] Quel est le problème avec l'utilisation de l'échappement spécifique à la base de données fonctions, et pourquoi était-ce mieux que les ajouts de barres obliques?

Rien de vraiment. C'est simplement le mantra expliquant pourquoi les AOP / préparées sont «meilleures». Ils sont bien meilleurs que les addlashes car ils prennent en charge de nombreux facteurs, y compris l'encodage. Voici un petit secret; PDO les utilise en interne, mais pas les addslashes...

[4.] Pourquoi les instructions préparées avec des frameworks et PDO sont-elles saluées comme l'étalon-or de SQL? Pourquoi sont-ils meilleurs? Pourquoi est-ce que je ne peux pas faire une injection SQL avec ceux-ci, alors que je pourrais le faire avec les moyens mentionnés précédemment?

Ils ne sont pas l'étalon-or , ils ne sont pas "plus" sécurisées que les fonctions spécifiques à la base de données et vous pouvez faire une injection SQL avec celles-ci également. Et non, vous ne pouvez pas faire d'injection SQL avec une entrée correctement nettoyée.

Comme pour toutes les technologies, les développeurs ont tendance à développer des tendances religieuses (fanatiques?) Pour tout ce qui est «nouveau». C'est pourquoi vous obtenez des ingénieurs certifiés Zend (TM) expérimentés qui vous conseillent de ne pas vous obliger à passer aux déclarations préparées.

La réalité, cependant, est que tout dépend de savoir ce que vous faites. Si vous chargez un article par son identifiant numérique, vous n'avez besoin d'aucune sorte d'échappatoire, encore moins PDO. Vous devez simplement vous assurer que ID est bien un entier.

D'un point de vue plus réaliste, la règle générale n'est pas d'utiliser PDO / instructions préparées, mais d'utiliser les bonnes fonctions, c'est-à-dire que vous doit utiliser mysql_real_escape_string () au lieu de ajoutelashes () ou mysql_escape_string().

[5.] Un programmeur ne parvient-il pas d'une manière ou d'une autre à tout foutre en l'air? À quoi doivent-ils faire attention?

Bien sûr! Mais ce n'est pas "ce qu'il faut rechercher" mais plutôt "savoir ce que vous faites".

Vous voyez, eval ($ _ GET ['code']) * est tout à fait légitime lorsqu'il est utilisé au bon endroit (comme un exécuteur de test PHP local).

Si vous utilisez un ORM pour exécuter une requête conditionnelle, vous entrez le code directement, il peut donc y avoir un chance d'obtenir une injection SQL si vous ne le faites pas correctement (dépend de l'ORM en question). (Hypothétique) Exemple:

  // update () définit la valeur d'une colonne avec une condition //// .-- l'échappement est automatique ici // | .-- injection SQL hypothétique // v vDb () - >update ('nom', $ _ GET ['nouveau nom']) - >where ('id ='. $ _ GET ['id']);  

(* Je ne peux qu'imaginer les innombrables professionnels se cogner la tête dessus)

+1. notamment pour signaler l'écueil des API mélangeant des requêtes paramétrées avec des parties dynamiques.
Une technique utile pour stocker des requêtes Web ou des données codées consiste à les encoder en base64 et à les stocker sous forme de chaîne.Cela n'empêche pas l'injection SQL ou les mauvaises données, mais il garantit au moins que rien de ce qui a été saisi ne sera utilisé tel quel.
rook
2011-05-08 01:25:29 UTC
view on stackexchange narkive permalink

À la fin de la journée, l'échappement de l'entrée doit être fait afin de protéger vos requêtes de l'injection SQL. Les bibliothèques de requêtes paramétrées comme PDO et ADODB utilisent l'échappement , tout ce qu'elles font est d'appliquer cette pratique d'une manière qui est implicitement sécurisée. Par contraste avec magic_quotes_gpc, PAS , c'est une approche fondamentalement imparfaite du problème.

1) Les échappements peuvent être problématiques si vous ne comprenez pas ce que vous faites. Ce type de problème est toujours exploitable si magic_quotes_gpc est activé.

  mysql_query ("select * from users where id =". Ajoutelashes ($ _ GET [id]));  

Exploit PoC: http: //localhost/vuln.php? id = sleep (30)

patch:

  mysql_query ("select * from users where id = '". addedlashes ($ _ GET [id]). "'");  

Leçon: Vous n'avez pas besoin de guillemets pour exploiter l'injection SQL.

2) Supposons que vous n'échappiez que les guillemets:

  mysql_query ("select * from users where name = '". htmlspecialchars ($ _ GET [name], ENT_QUOTES). "' and id = '". htmlspecialchars ($ _ GET [id], ENT_QUOTES). "'");  

Exploit PoC: http: //localhost/vuln.php? name = \ &id = + ou + sleep (30) / *

Patch:

  mysql_query ("select * from users where name = '". addedlashes ($ _ GET [name]). "' and id = '". ($ _GET [id]). "'");  

Leçon : Les contre-obliques sont tout aussi dangereuses comme guillemets.

3) Qu'en est-il de l'encodage de la langue?

  mysql_query ("SET CHARACTER SET 'gbk'"); mysql_query ("select * from user where name = '". / code> 

Exploit PoC: http: //localhost/vuln.php? name =% bf% 27 = sleep (30) / *

Patch:

  mysql_query ("SET CHARACTER SET 'gbk'"); mysql_query ("select * from user where name = '". mysql_real_escape_string ($ _ GET [name]). "'") ;  

Conclusion:

L'échappement est absolument nécessaire pour empêcher l'injection de SQL dans une application. En PHP, PDO et ADOB sont d'excellentes bibliothèques de requêtes paramétrées qui imposent l'échappement des entrées utilisateur. Le problème est que de nombreux programmeurs ne comprennent pas ce qu'est l'échappement. Avoir une bibliothèque pour appliquer cette politique de sécurité est la meilleure méthode de défense, car vous n'avez pas besoin de comprendre les règles d'échappement.

"Echaping est absolument nécessaire pour empêcher l'injection SQL dans une application", c'est tout simplement faux. Une approche beaucoup moins sujette aux erreurs que l'utilisation de l'échappement consiste à utiliser des requêtes paramétrées avec une partie de requête constante et toutes les données non approuvées dans les paramètres. Étant donné que les données ne font jamais partie de la chaîne de requête SQL, aucun échappement n'est nécessaire et la base de données fait ce qu'il faut. /// Veuillez ne pas suggérer d'utiliser des addlashes car une application PHP peut être vulnérable à l'attaque de charset même sans définir explicitement le charset à cause des configurations par défaut de MySQL par exemple.
Pour prendre le pilote mysqli comme exemple: La fonction [mysqlnd_stmt_execute_store_params] (http://codesearch.google.com/codesearch/p?hl=de#ceArhxvuL0U/Oem/php/ext/mysqlnd/mysqlnd_ps_codec.c&q=mysqlnd_ps_cdore_codec.c&q=mysqlnd_ps_codec.c&nd=mysqlnd_ps_cdore.c&ndstmys 1 & ct = rc) envoie les paramètres au serveur sous forme de données binaires en dehors de la chaîne de requête.
@Hendrik Brummermann Quelle fonction de requête paramétrée de niveau supérieur (http://php.net/manual/en/book.mysql.php) est prise en charge par cette fonction? Je pense que vous vous trompez sur la fonctionnalité de ce code. Je sais que c'est un abus de langage de dire "s'échapper est mauvais et que vous devriez utiliser PDO à la place".
L'ensemble associé de fonctions de requête de haut niveau qui finissent par appeler cette fonction de pilote interne est [prepare] (http://www.php.net/manual/en/mysqli.prepare.php), [bind_param] (http: // www.php.net/manual/en/mysqli-stmt.bind-param.php) et [execute] (http://www.php.net/manual/en/mysqli-stmt.execute.php). J'utilise moi-même la méthode d'échappement dans la plupart des cas, mais l'utilisation de requêtes paramétrées est une alternative valable. Et bien qu'il existe certains frameworks qui remplacent les paramètres dans l'instruction SQL (avec un échappement approprié), les fonctions de base de données les transmettent parallèlement à la requête.
@Hendrik Brummermann Je suis très sceptique à ce sujet. Principalement parce que le [code mysqli] (http://codesearch.google.com/codesearch/p?hl=de#ceArhxvuL0U/Oem/php/ext/mysqli/mysqli.c&q=mysqlnd_stmt_execute_store_params&d=3) n’appelle même pas cette fonction] (http://codesearch.google.com/codesearch?q=mysqlnd_stmt_execute_store_params&exact_package=http%3A%2F%2Fsvn.osgeo.org%2Fmapguide%2Ftrunk%2FMgDev&hl=de)
«Avoir une bibliothèque pour appliquer cette politique de sécurité est la meilleure méthode de défense, car vous n'avez pas besoin de comprendre les règles qui s'échappent» - Et c'est, mes amis, pourquoi nous échouons en matière de sécurité. La vérité est que le programmeur a besoin de savoir ce qu'il fait. ** Ne pas savoir est un problème de sécurité en soi. ** Utiliser PDO, etc., c'est comme utiliser OSX, vous savez que vous êtes en sécurité jusqu'à ce qu'il y ait suffisamment de vous pour que les pirates repensent leur stratégie - et quand ce virus disparaît, c'est Windows 98 tout à nouveau.
@Christian Sciberras Je suis d'accord. Malheureusement, les personnes qui comprennent vraiment ces problèmes sont très rares et sont là pour très cher.
@Rock, votre recherche google dans ce fichier n'a pas de succès car l'appel est imbriqué dans différents fichiers: mysqlnd_stmt_execute_store_params dans mysql_ps_codec.c est appelé par [mysqlnd_stmt_execute_generate_request] (http://goo.gl/QlQHk) dans lequel mysqlQlHk) méthode exportée [mysqlnd_stmt_execute] (http://goo.gl/c9GY4). [mysqli_mysqlnd.h] (http://goo.gl/9e42S) et [mysqlnd_libmysql_compat.h] (http://goo.gl/OnUa7) font le mappage à partir des fonctions mysql.
@Hendrik Brummermann Et le code mysqli n'utilise aucun de ces bruits. Si vous regardez le code mysqli, il construit sa propre structure MY_STMT où, par les paramètres individuels, * peut être * transmis séparément de la requête brute. Donc, vous avez partiellement raison, il existe une autre option que l'échappement pour mysql, mais la plupart des bibliothèques de requêtes paramétrées ne l'utilisent pas. De plus, il n'y a pas de différence de sécurité entre ces deux approches, mais la structure MY_STMT utilisera un peu moins de temps de bande passante / cpu.
Cut Copy
2011-08-18 02:15:49 UTC
view on stackexchange narkive permalink

À propos des fonctions d'échappement spécifiques à la base de données. Il existe de nombreux scénarios dans lesquels une injection SQL peut se produire, même si mysql_real_escape_string () a été utilisé. LIMIT et ORDER BY sont vraiment compliqués!

Ces exemples sont vulnérables à l'injection SQL:

  $ offset = isset ($ _ GET ['o'])? $ _GET ['o']: 0; $ offset = mysql_real_escape_string ($ offset); $ sql = "SELECT userid, username FROM sql_injection_test LIMIT $ offset, 10";  

ou

  $ order = isset ($ _ GET ['o'])? $ _GET ['o']: 'userid'; $ order = mysql_real_escape_string ($ order); $ sql = "SELECT userid, username FROM sql_injection_test ORDER BY` $ order` ";  

Dans les deux cas, vous ne pouvez pas utiliser 'pour protéger l'encapsulation.

source: L'injection SQL inattendue (lorsque l'échappement ne suffit pas) < - Lisez ceci

atdre
2011-05-06 21:57:56 UTC
view on stackexchange narkive permalink

Les filtres peuvent être contournés et les données qui entrent dans les instructions SQL peuvent provenir de plus d'endroits que la simple entrée de l'utilisateur. Les points d'entrée dans une source / récepteur influencé par SQL peuvent être stockés (d'ordre supérieur), par exemple, mais il est clair que les paramètres HTTP GET et les paramètres POST des formulaires HTML ne sont pas les seuls moyens de saisie utilisateur.

Les requêtes paramétrées ne rendent pas nécessairement vos instructions SQL exemptes d'injections. Ils nécessitent également la liaison de variables, la suppression des opérations / concaténations de chaînes et d'éviter certains problèmes de sécurité avec une large gamme de clauses SQL.

La plupart des développeurs oublient également de vérifier leurs composants tiers et autres dépendances pour Problèmes d'injection SQL, et parfois ne réalisent pas que ces inclusions pourraient rendre leur propre code vulnérable.

La meilleure chose à faire est de faire appel à une société de conseil en sécurité des applications pour préparer vos applications à la préparation de la production et pour former votre ou vos équipes appdev à intégrer les contrôles de sécurité des applications à leur technologie de processus et de développement.

getahobby
2011-05-07 05:00:29 UTC
view on stackexchange narkive permalink

Pour développer la réponse de Hendrick. Il est facile de considérer real_escape_string comme une solution miracle alors qu'en réalité ce n'est pas le cas. J'ai vu des gens utiliser cette fonction lorsqu'ils voulaient utiliser intval ou convertir l'entrée en un entier à la place. Vous pouvez toujours être injecté si vous utilisez la chaîne d'échappement dans le mauvais contexte.

xlinex
2014-10-09 03:48:51 UTC
view on stackexchange narkive permalink

Puisque le but est de vous aider à apprendre à écrire du code décent et pas seulement à copier une recette, je laisserai quelques indices.

  • Si nous quittons l'encodage, il y a de nombreuses façons d'injecter sql et toutes ne nécessitent pas que vous ajoutiez "ou" ou ", donc Addslashes est fondamentalement une solution boiteuse utilisée par les développeurs boiteux et non qualifiés ... (ceux dont vous ne devriez pas lire de code).

  • Celui-ci ne se produit pas souvent mais, il existe en fait un vecteur où l'attaquant peut exploiter une instruction préparée, dans certains moteurs de base de données. Ce n'est pas courant mais vous pouvez vous en souvenir l'instruction préparée utilise une instruction mais avec le type de colonne de métadonnées de table, la taille ....

  • Une autre erreur boiteuse habituelle est de gérer les recherches dans les requêtes avec des goûts ... comment cela fonctionne, vous pouvez faire des choses intéressantes ....

Faites vos recherches, ne faites jamais confiance à une entrée, n'utilisez jamais autre chose qu'une déclaration préparée, ignorez quiconque vous dit d'utiliser escape fu ...

Et vous devriez être prudent e, rappelez-vous qu'il ne sert à rien d'obtenir autre chose que ce que vous attendez, donc l'api typé fort est votre ami;).

vous devez nettoyer cette réponse - orthographe, grammaire, formatage étrange - veuillez consacrer un peu plus de temps à vos réponses


Ce Q&R a été automatiquement traduit de la langue anglaise.Le contenu original est disponible sur stackexchange, que nous remercions pour la licence cc by-sa 3.0 sous laquelle il est distribué.
Loading...