151 votes

Puis-je me protéger contre les injections SQL en échappant aux guillemets simples et en entourant les entrées de l'utilisateur de guillemets simples ?

Je me rends compte que les requêtes SQL paramétrées sont le meilleur moyen d'assainir l'entrée de l'utilisateur lors de la construction de requêtes qui contiennent l'entrée de l'utilisateur, mais je me demande ce qui est mal de prendre l'entrée de l'utilisateur et d'échapper tous les guillemets simples et d'entourer toute la chaîne de caractères avec des guillemets simples. Voici le code :

sSanitizedInput = "'" & Replace(sInput, "'", "''") & "'"

Tous les guillemets simples que l'utilisateur saisit sont remplacés par des guillemets doubles, ce qui élimine la possibilité pour l'utilisateur de terminer la chaîne de caractères, de sorte que tout ce qu'il peut saisir, comme les points-virgules, les pourcentages, etc.

Nous utilisons Microsoft SQL Server 2000, pour lequel je crois que le guillemet simple est le seul délimiteur de chaîne et le seul moyen d'échapper au délimiteur de chaîne. Il n'y a donc aucun moyen d'exécuter tout ce que l'utilisateur tape.

Je ne vois aucun moyen de lancer une attaque par injection SQL contre ce système, mais je me rends compte que si ce système était aussi infaillible qu'il me semble, quelqu'un d'autre y aurait déjà pensé et ce serait une pratique courante.

Quel est le problème avec ce code ? Y a-t-il un moyen de faire passer une attaque par injection SQL au-delà de cette technique d'assainissement ? Un exemple d'entrée utilisateur qui exploite cette technique serait très utile.


UPDATE :

Je ne connais toujours pas de moyen de lancer efficacement une attaque par injection SQL contre ce code. Quelques personnes ont suggéré qu'une barre oblique inversée permettrait d'échapper à une apostrophe et de laisser l'autre à la fin de la chaîne de manière à ce que le reste de la chaîne soit exécuté dans le cadre de la commande SQL, et je réalise que cette méthode fonctionnerait pour injecter du SQL dans une base de données MySQL, mais dans SQL Server 2000, le seul moyen (que j'ai pu trouver) d'échapper à une apostrophe est d'utiliser une autre apostrophe ; les barres obliques inversées ne le font pas.

Et à moins qu'il n'existe un moyen d'empêcher l'échappement du guillemet simple, aucune des autres entrées de l'utilisateur ne sera exécutée car elles seront toutes considérées comme une seule chaîne contiguë.

Je comprends qu'il existe de meilleurs moyens d'assainir les entrées, mais je suis vraiment plus intéressé à savoir pourquoi la méthode que j'ai fournie ci-dessus ne fonctionne pas. Si quelqu'un connaît un moyen spécifique de monter une attaque par injection SQL contre cette méthode d'assainissement, je serais ravi de le voir.

21 votes

@BryanH Admettre ne pas comprendre comment la sagesse communément admise s'applique à un cas spécifique et demander un exemple sur ce cas spécifique n'est pas de l'orgueil, c'est de l'humilité. En revanche, s'énerver lorsque quelqu'un demande un exemple expliquant pourquoi la sagesse communément admise a raison peut passer pour de l'arrogance. Raisonner à l'aide d'exemples spécifiques est souvent un excellent moyen d'enquêter et d'apprendre. La façon dont le PO a abordé ce doute a été très utile pour ma compréhension du sujet, en particulier lorsqu'il a expliqué la réponse qu'il a trouvée.

0 votes

@patrik Je viens de tomber sur ce sujet alors que je travaille sur le même morceau de code mais en essayant d'échapper la chaîne de caractères et d'imbriquer une requête. Avez-vous trouvé la solution ?

1 votes

@3therk1ll il vaut mieux ne pas essayer, il est préférable d'utiliser le SQL paramétré : blog.codinghorror.com/

91voto

AviD Points 8413

Tout d'abord, c'est une mauvaise pratique. La validation des entrées est toujours nécessaire, mais elle est aussi toujours incertaine.
Pire encore, la validation par liste noire est toujours problématique, il est bien mieux de définir explicitement et strictement les valeurs/formats que vous acceptez. Certes, ce n'est pas toujours possible, mais dans une certaine mesure, cela doit toujours être fait.
Quelques documents de recherche sur le sujet :

Le fait est que toutes les listes noires que vous établissez (et les listes blanches trop permissives) peuvent être contournées. Le dernier lien vers mon article montre des situations où même l'échappement des guillemets peut être contourné.

Même si ces situations ne s'appliquent pas à vous, c'est toujours une mauvaise idée. De plus, à moins que votre application ne soit très petite, vous allez devoir vous occuper de la maintenance, et peut-être d'une certaine gouvernance : comment vous assurer que tout est fait correctement, partout et tout le temps ?

La façon correcte de le faire :

  • Validation de la liste blanche : type, longueur, format ou valeurs acceptées
  • Si vous voulez établir une liste noire, allez-y. L'échappement des citations est une bonne chose, mais dans le cadre des autres mesures d'atténuation.
  • Utiliser les objets Commande et Paramètre, pour préparer et valider
  • Appeler uniquement les requêtes paramétrées.
  • Mieux encore, utilisez exclusivement les procédures stockées.
  • Évitez d'utiliser le SQL dynamique et n'utilisez pas la concaténation de chaînes de caractères pour construire des requêtes.
  • Si vous utilisez des SP, vous pouvez également limiter les autorisations dans la base de données pour exécuter uniquement les SP nécessaires, et ne pas accéder directement aux tables.
  • vous pouvez aussi facilement vérifier que l'ensemble de la base de code n'accède à la BD qu'à travers des SP...

3 votes

Lorsqu'ils sont utilisés correctement, le SQL dynamique et la concaténation de chaînes de caractères peuvent être utilisés en toute sécurité avec des requêtes paramétrées (c'est-à-dire avec des sp_executesql au lieu de EXEC ). En d'autres termes, vous pouvez générer dynamiquement votre instruction SQL tant qu'aucun des textes concaténés ne provient de l'utilisateur. Cela présente également des avantages en termes de performances ; sp_executesql prend en charge la mise en cache.

2 votes

@Brian, bien sûr :). Mais en réalité, combien de fois voyez-vous des programmeurs faire cela ? De plus, le scénario typique où le SQL dynamique est "nécessaire", nécessite l'entrée de l'utilisateur comme partie de la requête (supposée). Si vous pouviez faire sp_executesql, vous n'auriez (généralement) pas besoin du sql dynamique en premier lieu.

0 votes

J'ai finalement rencontré une situation qui m'a fait réaliser qu'il est possible d'utiliser l'unicode pour contourner le remplacement des chaînes de caractères. Le texte d'entrée a été tapé dans Word, qui a changé l'apostrophe de la version droite vers le bas en une apostrophe "frisée" (qui ressemble plus à une virgule), qui n'a pas été affectée par le remplacement de chaîne mais a été traitée comme un délimiteur de chaîne par SQL Server. Merci pour la réponse AviD (et tous les autres) !

42voto

AviD Points 8413

Ok, cette réponse sera liée à la mise à jour de la question :

"Si quelqu'un connaît un moyen spécifique de monter une attaque par injection SQL contre cette méthode d'assainissement, j'aimerais bien le voir."

Outre l'échappement de la barre oblique inversée de MySQL, et compte tenu du fait que nous parlons en fait de MSSQL, il existe en fait 3 façons possibles d'injecter votre code en SQL

sSanitizedInput = "'" & Replace(sInput, "'", "''") & "'"

Tenez compte du fait qu'elles ne seront pas toutes valables à tout moment et qu'elles dépendent fortement du code qui les entoure :

  1. Injection SQL de second ordre - si une requête SQL est reconstruite à partir de données extraites de la base de données. après s'être échappé les données sont concaténées sans marquage et peuvent être injectées indirectement par SQL. Voir
  2. Troncature de chaîne - (un peu plus compliqué) - Le scénario est que vous avez deux champs, disons un nom d'utilisateur et un mot de passe, et le SQL les concatène tous les deux. Et les deux champs (ou juste le premier) ont une limite stricte de longueur. Par exemple, le nom d'utilisateur est limité à 20 caractères. Disons que vous avez ce code :
username = left(Replace(sInput, "'", "''"), 20)

Ce que vous obtenez alors, c'est le nom d'utilisateur, échappé, puis réduit à 20 caractères. Le problème ici est que je vais placer mon guillemet dans le 20ème caractère (par exemple après 19 a), et votre guillemet d'échappement sera coupé (dans le 21ème caractère). Ensuite, le SQL

sSQL = "select * from USERS where username = '" + username + "'  and password = '" + password + "'"

combiné avec le nom d'utilisateur malformé mentionné plus haut, le mot de passe sera déjà à l'extérieur de les guillemets, et contiendra simplement la charge utile directement.
3. Contrebande d'Unicode - Dans certaines situations, il est possible de faire passer un caractère unicode de haut niveau qui regarde comme une citation, mais n'est pas - jusqu'à ce qu'il arrive à la base de données, où soudainement c'est . Puisque ce n'est pas une citation lorsque vous la validez, elle passera facilement... Voir ma réponse précédente pour plus de détails, et le lien vers la recherche originale.

28voto

Nick Johnson Points 79909

En un mot : Ne faites jamais d'évasion de requêtes vous-même. Vous risquez de vous tromper. Utilisez plutôt des requêtes paramétrées, ou si vous ne pouvez pas le faire pour une raison quelconque, utilisez une bibliothèque existante qui le fait pour vous. Il n'y a aucune raison de le faire vous-même.

3 votes

Qu'en est-il si vous devez traiter quelque chose comme "Google Fusion tables" où, afaik, il n'y a aucune bibliothèque d'abstraction disponible qui supporte son dialecte ? Que suggérez-vous ?

0 votes

La question n'est pas de savoir qui est le plus sage, mais de savoir exactement comment une solution particulière échoue réellement. Si vous ne le savez pas, alors vous n'avez pas de réponse à cette question.

21voto

Jørn Jensen Points 589

Je réalise que cela fait longtemps que la question a été posée, mais

Une façon de lancer une attaque contre la procédure "citer l'argument" est de tronquer les chaînes de caractères. Selon MSDN, dans SQL Server 2000 SP4 (et SQL Server 2005 SP1), une chaîne trop longue sera discrètement tronquée.

Lorsque vous citez une chaîne de caractères, celle-ci augmente en taille. Chaque apostrophe est répétée. Cela peut ensuite être utilisé pour pousser des parties du SQL en dehors du tampon. Ainsi, vous pouvez effectivement supprimer des parties d'une clause "where".

Cela serait probablement utile dans le cas d'une page d'administration d'utilisateur où l'on pourrait abuser de l'instruction "update" pour ne pas faire toutes les vérifications qu'elle est censée faire.

Donc, si vous décidez de citer tous les arguments, assurez-vous de connaître la taille des chaînes de caractères et veillez à ne pas vous heurter à la troncature.

Je vous recommande d'opter pour les paramètres. Toujours. J'aimerais juste pouvoir le faire respecter dans la base de données. Et comme effet secondaire, vous avez plus de chances d'obtenir de meilleurs résultats dans le cache parce que davantage de déclarations se ressemblent. (C'était certainement vrai sur Oracle 8)

1 votes

Après avoir posté, j'ai décidé que le post d'AviD couvrait ce sujet, et de manière plus détaillée. J'espère que mon message sera quand même utile à quelqu'un.

9voto

tom.dietrich Points 3122

L'assainissement des intrants n'est pas quelque chose que vous devez négliger. Utilisez tout votre cul. Utilisez des expressions régulières sur les champs de texte. Essayez de convertir vos données numériques dans le type numérique approprié et signalez une erreur de validation si cela ne fonctionne pas. Il est très facile de rechercher des modèles d'attaque dans vos entrées, comme ' --. Supposez que toutes les entrées de l'utilisateur sont hostiles.

4 votes

Et quand tu manques ça ONE affaire sur ONE entrée, vous êtes pwnd.

4 votes

"Certaines personnes, lorsqu'elles sont confrontées à un problème, pensent "je sais, je vais utiliser des expressions régulières". Maintenant, ils ont deux problèmes."

1 votes

@mickeyf Je sais que c'est un sentiment commun mais honnêtement les expressions régulières sont assez géniales une fois qu'on les a grepées.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X