Je sais que PreparedStatements évite / empêche l'injection SQL. Comment fait-il cela? La requête de formulaire finale construite à l'aide de PreparedStatements sera-t-elle une chaîne ou autre?
java
sql
jdbc
prepared-statement
sql-injection
Prabhu R
la source
la source
Réponses:
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 comme paramètre pour votre instruction préparée, mais que vous créez plutôt votre commande SQL en joignant des chaînes ensemble, vous êtes toujours vulnérable aux injections SQL, même lorsque vous utilisez des instructions préparées.
la source
Considérez deux façons de faire la même chose:
Ou
Si "utilisateur" provenait de l'entrée utilisateur et que l'entrée utilisateur était
Ensuite, dans un premier temps, vous seriez arrosé. Dans le second, vous seriez en sécurité et Little Bobby Tables serait inscrit dans votre école.
la source
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 ci-dessous,
Phase d'analyse et de normalisation: dans cette phase, la syntaxe et la sémantique de la requête 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 beaucoup d'autres tâches à faire, mais n'allons pas dans les détails.
Phase de compilation: Dans cette phase, les mots-clés utilisés dans la requête tels que select, from, where, etc. sont convertis en un format compréhensible par la machine. C'est la phase où la requête est interprétée et l'action correspondante à entreprendre est décidée. Il a également beaucoup d'autres tâches à faire, mais n'allons pas dans les détails.
Plan d'optimisation des requêtes: dans cette phase, l'arbre de décision est créé pour trouver les moyens d'exécuter la requête. Il détecte 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.
Cache: le meilleur plan sélectionné dans le plan d'optimisation des requêtes est stocké dans le cache, de sorte qu'à chaque fois que la même requête arrive, elle n'a pas à passer à nouveau par la phase 1, la phase 2 et la phase 3. Lors de la prochaine requête, elle sera vérifiée directement dans le cache et récupérée à partir de là pour être exécutée.
Phase d'exécution: dans cette phase, la requête fournie est exécutée et les données sont renvoyées à l'utilisateur en tant
ResultSet
qu'objet.Comportement de l'API PreparedStatement aux étapes ci-dessus
Les PreparedStatements ne sont pas des requêtes SQL complètes et contiennent des espaces réservés, qui au moment de l'exécution sont remplacés par des données réelles fournies par l'utilisateur.
Chaque fois qu'un PreparedStatment contenant des espaces réservés est transmis au moteur SQL Server, il passe par les phases ci-dessous
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. La requête à ce stade est déjà compilée et convertie 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.
Désormais, au moment de l'exécution, lorsque les données fournies par l'utilisateur arrivent, 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.
(N'oubliez pas qu'une fois les espaces réservés remplacés par les données utilisateur, la requête finale n'est pas compilée / interprétée à nouveau et le moteur SQL Server traite les données utilisateur comme des données pures et non comme un SQL qui doit être analysé ou compilé à nouveau; c'est la beauté de PreparedStatement. )
Si la requête n'a pas à passer à 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 et n'ont aucune signification pour le moteur SQL Server et exécutent directement la requête.
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 n'est compilée qu'une seule fois et la requête compilée mise en cache est récupérée en permanence pour remplacer les données utilisateur et s'exécuter.
En raison de la fonctionnalité de compilation unique de PreparedStatement, il est exempt d'attaque par injection SQL.
Vous pouvez obtenir une explication détaillée avec un exemple ici: https://javabypatel.blogspot.com/2015/09/how-prepared-statement-in-java-prevents-sql-injection.html
la source
Le SQL utilisé dans un PreparedStatement est précompilé sur le pilote. À partir de là, les paramètres sont envoyés au pilote sous forme de valeurs littérales et non de parties exécutables de SQL; donc aucun SQL ne peut être injecté à l'aide d'un paramètre. Un autre effet secondaire bénéfique de PreparedStatements (précompilation + envoi de paramètres uniquement) est l'amélioration des performances lors de l'exécution de l'instruction plusieurs fois, même avec des valeurs différentes pour les paramètres (en supposant que le pilote prend en charge PreparedStatements) car le pilote n'a pas à effectuer l'analyse SQL et la compilation chacun heure à laquelle les paramètres changent.
la source
Je suppose que ce sera une chaîne. Mais les paramètres d'entrée seront envoyés à la base de données et les conversions / 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 CAST / Conversion fonctionne.
Si cela fonctionne, cela pourrait en créer une déclaration finale.
Essayez un exemple avec une instruction SQL acceptant un paramètre numérique.
Maintenant, essayez de transmettre une variable de chaîne (avec un contenu numérique acceptable comme paramètre numérique). Cela soulève-t-il une erreur?
Maintenant, essayez de passer une variable de chaîne (avec un contenu qui n'est pas acceptable en tant que paramètre numérique). Voyez ce qui se passe?
la source
La déclaration préparée est plus sûre. Il convertira un paramètre dans le type spécifié.
Par exemple
stmt.setString(1, user);
, convertira leuser
paramètre en chaîne.Supposons que le paramètre contienne une chaîne SQL contenant une commande exécutable : l'utilisation d'une instruction préparée ne le permettra pas.
Il ajoute un métacaractère (aka conversion automatique) à cela.
Cela le rend plus sûr.
la source
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»); Étudiants DROP TABLE; - "comme entrée, cela provoque une injection SQL
Comment une déclaration préparée empêche cela?
Requête de chaîne = "INSÉRER DANS LES VALEURS DES élèves ('" + ": nom" + "')"
parameters.addValue ("nom", utilisateur);
=> lorsque l'utilisateur saisit à nouveau «Robert»); Étudiants DROP TABLE; - «, la chaîne d'entrée est précompilée sur le pilote en tant que valeurs littérales et je suppose qu'elle peut être castée comme:
CAST («Robert»); Étudiants DROP TABLE; - '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/
la source
CAST(‘Robert’);
deCAST(‘Robert’); DROP TABLE students; –‘ AS varchar(30))
se briserait, puis elle abandonnerait la table si c'était le cas. Cela arrête l'injection, donc je pense que l'exemple n'est tout simplement pas assez complet pour expliquer le scénario.Affirmation préparée:
1) La précompilation et la mise en cache côté base de données de l'instruction SQL permettent une exécution globalement 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 cela nécessite que vous utilisiez l'une des méthodes SetXxx () PreparedStatement pour définir la valeur.
la source
Comme expliqué dans cet article , 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:
Non seulement SQL, mais même JPQL ou HQL peuvent être compromis si vous n'utilisez pas de paramètres de liaison.
En fin de compte, vous ne devez jamais utiliser la concaténation de chaînes lors de la création d'instructions SQL. Utilisez une API dédiée à cet effet:
la source
Dans les déclarations préparées, l'utilisateur est obligé de saisir des données en tant que paramètres. Si l'utilisateur entre des instructions vulnérables telles que DROP TABLE ou SELECT * FROM USERS, les données ne seront pas affectées car elles seront considérées comme des paramètres de l'instruction SQL
la source