web-dev-qa-db-fra.com

Comment un état préparé évite-t-il ou empêche-t-il une injection SQL?

Je sais que PreparedStatements évite/empêche l'injection SQL. Comment ça fait ça? La requête de formulaire finale construite à l'aide de PreparedStatements sera-t-elle une chaîne ou autrement?

107
Prabhu R

Le problème avec l'injection SQL est qu'une entrée utilisateur est utilisée dans le cadre de l'instruction SQL. En utilisant des instructions préparées, vous pouvez forcer l'entrée utilisateur à être traitée comme le contenu d'un paramètre (et non comme une partie de la commande SQL).

Mais si vous n'utilisez pas l'entrée utilisateur en tant que paramètre pour votre instruction préparée, mais construisez plutôt votre commande SQL en joignant des chaînes, vous êtes toujours vulnérable aux injections SQL même lorsque vous utilisez des instructions préparées.

66
tangens

Considérons deux manières de faire la même chose:

PreparedStatement stmt = conn.createStatement("INSERT INTO students VALUES('" + user + "')");
stmt.execute();

Ou

PreparedStatement stmt = conn.prepareStatement("INSERT INTO student VALUES(?)");
stmt.setString(1, user);
stmt.execute();

Si "utilisateur" provient d'une entrée utilisateur et que cette entrée est

Robert'); DROP TABLE students; --

Ensuite, dans un premier temps, vous seriez arrosé. Dans le second cas, vous seriez en sécurité et Little Bobby Tables serait inscrit à votre école.

181
Paul Tomblin

Pour comprendre comment PreparedStatement empêche l'injection SQL, nous devons comprendre les phases d'exécution de la requête SQL.

1. Phase de compilation. 2. Phase d'exécution.

Chaque fois que le moteur de serveur SQL reçoit une requête, il doit passer par les phases suivantes,

Query Execution Phases

  1. Phase d'analyse et de normalisation: Dans cette phase, la syntaxe et la sémantique de Query sont vérifiées. Il vérifie si la table de références et les colonnes utilisées dans la requête existent ou non. Il a également de nombreuses autres tâches à accomplir, mais n'allons pas dans les détails.

  2. Phase de compilation: Au cours de cette phase, les mots clés utilisés dans les requêtes, tels que select, from, etc. C'est la phase où la requête est interprétée et où l'action correspondante à entreprendre est décidée. Il a également de nombreuses autres tâches à accomplir, mais n'allons pas dans les détails.

  3. Plan d'optimisation de la requête: Au cours de cette phase, un arbre de décision est créé pour rechercher les moyens permettant d'exécuter une requête. Il détermine le nombre de façons dont la requête peut être exécutée et le coût associé à chaque manière d’exécuter la requête. Il choisit le meilleur plan pour exécuter une requête.

  4. Cache: Le meilleur plan sélectionné dans le plan d'optimisation de la requête est stocké dans le cache, de sorte que la prochaine fois que la même requête est reçue, elle n'a pas à passer par Phase 1, Phase 2 et Phase 3 à nouveau. La prochaine fois que la requête arrivera, elle sera vérifiée directement dans le cache et récupérée à partir de là pour être exécutée.

  5. Phase d'exécution: Au cours de cette phase, la requête fournie est exécutée et les données sont renvoyées à l'utilisateur sous la forme ResultSet object.

Comportement de l'API PreparedStatement aux étapes ci-dessus

  1. PreparedStatements ne sont pas des requêtes SQL complètes et contiennent un ou des espaces réservés qui, au moment de l'exécution, sont remplacés par les données réelles fournies par l'utilisateur.

  2. Chaque fois qu'un état PreparedStatment contenant des espaces réservés est transmis au moteur SQL Server, il passe par les phases suivantes.

    1. Phase d'analyse et de normalisation
    2. Phase de compilation
    3. Plan d'optimisation des requêtes
    4. Cache (la requête compilée avec des espaces réservés est stockée dans le cache.)

UPDATE utilisateur set username =? et mot de passe =? O id =?

  1. La requête ci-dessus sera analysée, compilée avec des espaces réservés comme traitement spécial, optimisée et mise en cache. À ce stade, les requêtes sont déjà compilées et converties dans un format compréhensible par la machine. Nous pouvons donc dire que la requête stockée dans le cache est précompilée et que seuls les espaces réservés doivent être remplacés par des données fournies par l'utilisateur.

  2. Désormais, au moment de l'exécution, lorsque les données fournies par l'utilisateur entrent, la requête précompilée est extraite du cache et les espaces réservés sont remplacés par des données fournies par l'utilisateur.

PrepareStatementWorking

(N'oubliez pas que, une fois que les espaces réservés ont été remplacés par des données utilisateur, la requête finale n'est plus compilée/interprétée et le moteur SQL Server traite les données utilisateur comme des données pures et non comme des instructions SQL à analyser ou à compiler. encore une fois, c’est la beauté de PreparedStatement.)

S'il n'est pas nécessaire que la requête passe à nouveau par la phase de compilation, les données remplacées sur les espaces réservés sont traitées comme des données pures. Elles n'ont aucune signification pour le moteur SQL Server et la requête est directement exécutée.

Remarque: C’est la phase de compilation après la phase d’analyse qui comprend/interprète la structure de la requête et lui donne un comportement significatif. Dans le cas de PreparedStatement, la requête est compilée une seule fois et la requête compilée en cache est captée à tout moment pour remplacer les données utilisateur et s'exécuter.

Grâce à la fonctionnalité de compilation unique de PreparedStatement, celui-ci est exempt d'attaque par injection SQL.

Vous pouvez obtenir une explication détaillée avec un exemple ici: http://javabypatel.blogspot.in/2015/09/how-prepared-statement-in-Java-prevents-sql-injection.html

96
Jayesh

Le SQL utilisé dans PreparedStatement est précompilé sur le pilote. À partir de ce moment, les paramètres sont envoyés au pilote sous forme de valeurs littérales et non de parties exécutables de SQL; ainsi, aucun SQL ne peut être injecté à l'aide d'un paramètre. Un autre effet bénéfique de PreparedStatements (précompilation + envoi de paramètres uniquement) est l'amélioration des performances lorsque l'instruction est exécutée plusieurs fois, même si les valeurs des paramètres sont différentes (en supposant que le pilote prenne en charge PreparedStatements), car le pilote n'a pas à analyser ni à compiler SQL. temps les paramètres changent.

26
Travis Heseman

La déclaration préparée est plus sécurisée. Cela convertira un paramètre dans le type spécifié.

Par exemple, stmt.setString(1, user); convertira le paramètre user en chaîne.

Supposons que le paramètre contenant une chaîne SQL contenant une commande exécutable: utiliser une instruction préparée ne le permettra pas.

Il ajoute le métacaractère (conversion automatique) à cela.

Cela le rend plus sûr.

3
Guru R Handa

Je devinez ce sera une chaîne. Mais les paramètres d'entrée seront envoyés à la base de données et les transformations/conversions appropriées seront appliquées avant la création d'une instruction SQL réelle.

Pour vous donner un exemple, il pourrait essayer de voir si le CAST/Conversion fonctionne.
Si cela fonctionne, cela pourrait créer une déclaration finale.

   SELECT * From MyTable WHERE param = CAST('10; DROP TABLE Other' AS varchar(30))

Essayez un exemple avec une instruction SQL acceptant un paramètre numérique.
Maintenant, essayez de passer une variable chaîne (avec un contenu numérique acceptable en tant que paramètre numérique). Cela soulève-t-il une erreur?

Maintenant, essayez de passer une variable de chaîne (avec un contenu non acceptable en tant que paramètre numérique). Voir ce qui se passe?

3
shahkalpesh

Injection SQL: lorsque l'utilisateur a la possibilité de saisir quelque chose qui pourrait faire partie de l'instruction SQL

Par exemple:

Requête de chaîne = "INSÉRER DANS LES VALEURS des étudiants ('" + utilisateur + "") "

lorsque l’utilisateur saisit "Robert"); DROP TABLE étudiants; - ”en entrée, cela provoque une injection SQL

Comment déclaration préparée empêche cela?

Requête de chaîne = "INSERER DANS LES VALEURS des étudiants ('" + ": nom" + "") "

parameters.addValue (“name”, utilisateur);

=> lorsque l’utilisateur saisit à nouveau "Robert’); DROP TABLE étudiants; - “, la chaîne d'entrée est précompilée sur le pilote sous forme de valeurs littérales et je suppose qu'elle peut être exprimée comme suit:

CAST ("Robert"); DROP TABLE étudiants; - "AS varchar (30))

Donc à la fin, la chaîne sera littéralement insérée comme nom de la table.

http://blog.linguiming.com/index.php/2018/01/10/why-prepared-statement-avoids-sql-injection/

2
jack

Comme expliqué dans this post , le PreparedStatement seul ne vous aide pas si vous êtes toujours en train de concaténer des chaînes.

Par exemple, un attaquant non autorisé peut toujours effectuer les opérations suivantes:

  • appeler une fonction de veille pour que toutes vos connexions à la base de données soient occupées, rendant ainsi votre application indisponible
  • extraire des données sensibles de la base de données
  • en contournant l'authentification de l'utilisateur

Non seulement SQL, mais même JPQL ou HQL peuvent être compromis si vous n'utilisez pas de paramètres de liaison.

En bout de ligne, vous ne devez jamais utiliser la concaténation de chaînes lors de la construction d'instructions SQL. Utilisez une API dédiée à cet effet:

1
Vlad Mihalcea

Affirmation préparée:

1) La précompilation et la mise en cache côté SQL de l’instruction SQL permettent une exécution plus rapide et la possibilité de réutiliser la même instruction SQL par lots.

2) Prévention automatique des attaques par injection SQL par échappement intégré des guillemets et autres caractères spéciaux. Notez que pour cela, vous devez utiliser l’une des méthodes PreparedStatement setXxx () pour définir la valeur.

1
Mukesh Kumar