L'idée est très simple: la requête et les données sont envoyées séparément au serveur de base de données .
C'est tout.
La racine du problème d'injection SQL réside dans le mélange du code et des données.
En fait, notre requête SQL est un programme légitime . Et nous créons un tel programme de manière dynamique, en ajoutant des données à la volée. Ainsi, les données peuvent interférer avec le code du programme et même le modifier, comme le montre chaque exemple d'injection SQL (tous les exemples en PHP / Mysql):
$expected_data = 1;
$query = "SELECT * FROM users where id=$expected_data";
produira une requête régulière
SELECT * FROM users where id=1
tandis que ce code
$spoiled_data = "1; DROP TABLE users;"
$query = "SELECT * FROM users where id=$spoiled_data";
produira une séquence malveillante
SELECT * FROM users where id=1; DROP TABLE users;
Cela fonctionne parce que nous ajoutons les données directement au corps du programme et qu'elles deviennent une partie du programme, de sorte que les données peuvent modifier le programme, et en fonction des données transmises, nous aurons soit une sortie régulière, soit une table users
supprimée.
Alors qu'en cas d'instructions préparées, nous ne modifions pas notre programme, il reste intact.
C'est le point.
Nous envoyons d'abord un programme au serveur
$db->prepare("SELECT * FROM users where id=?");
où les données sont remplacées par une variable appelée paramètre ou espace réservé.
Notez qu'exactement la même requête est envoyée au serveur, sans aucune donnée! Et puis nous envoyons les données avec la deuxième requête, essentiellement séparée de la requête elle-même:
$db->execute($data);
il ne peut donc pas modifier notre programme et faire du mal.
Assez simple - n'est-ce pas?
La seule chose que je dois ajouter qui est toujours omise dans chaque manuel:
Les instructions préparées ne peuvent protéger que les littéraux de données , mais ne peuvent être utilisées avec aucune autre partie de requête.
Donc, une fois que nous devons ajouter, disons, un identifiant dynamique - un nom de champ, par exemple - les instructions préparées ne peuvent pas nous aider. J'ai expliqué la question récemment , donc je ne me répéterai pas.
$spoiled_data = "1; DROP TABLE users;"
->$query = "SELECT * FROM users where id=$spoiled_data";
, par rapport à:$db->prepare("SELECT * FROM users where id=?");
->$data = "1; DROP TABLE users;"
->$db->execute($data);
. Ne feront-ils pas la même chose?Voici SQL pour mettre en place un exemple:
La classe Inject est vulnérable à l'injection SQL. La requête est collée dynamiquement avec l'entrée utilisateur. Le but de la requête était d'afficher des informations sur Bob. Soit un salaire, soit une prime, en fonction de l'entrée de l'utilisateur. Mais l'utilisateur malveillant manipule l'entrée corrompant la requête en plaçant l'équivalent d'un 'or true' à la clause where pour que tout soit renvoyé, y compris les informations sur Aaron qui étaient censées être cachées.
En exécutant ceci, le premier cas est avec une utilisation normale, et le second avec l'injection malveillante:
Vous ne devez pas créer vos instructions SQL avec une concaténation de chaînes d'entrée utilisateur. Non seulement il est vulnérable à l'injection, mais il a également des implications de mise en cache sur le serveur (l'instruction change, donc moins susceptible d'obtenir un hit de cache d'instruction SQL alors que l'exemple de liaison exécute toujours la même instruction).
Voici un exemple de Binding pour éviter ce type d'injection:
L'exécuter avec la même entrée que l'exemple précédent montre que le code malveillant ne fonctionne pas car il n'y a pas de paymentType correspondant à cette chaîne:
la source
PREPARE
crée une instruction nommée fixe qui est déjà analysée (c'est-à-dire que l'instruction ne changera plus quelle que soit l'entrée) tandis queEXECUTE
exécutera l'instruction nommée liant les paramètres. Comme ilPREPARE
n'y a que la durée de la session, il semble vraiment qu'il soit destiné à des raisons de performances, et non à empêcher l'injection via des scripts psql. Pour l'accès psql, pourrait donner des autorisations aux procédures stockées et lier les paramètres dans les procs.Fondamentalement, avec des instructions préparées, les données provenant d'un pirate informatique potentiel sont traitées comme des données - et il n'y a aucun moyen qu'elles puissent être mélangées avec votre application SQL et / ou interprétées comme SQL (ce qui peut se produire lorsque les données transmises sont placées directement dans votre SQL de l'application).
En effet, les instructions préparées «préparent» d'abord la requête SQL pour trouver un plan de requête efficace et envoient les valeurs réelles qui proviennent vraisemblablement d'un formulaire plus tard - à ce moment-là, la requête est effectivement exécutée.
Plus d'informations ici:
Instructions préparées et injection SQL
la source
J'ai lu les réponses et j'ai toujours ressenti le besoin de souligner le point clé qui éclaire l'essence des déclarations préparées. Considérez deux façons d'interroger sa base de données où l'entrée de l'utilisateur est impliquée:
Approche naïve
L'un concatène l'entrée utilisateur avec une chaîne SQL partielle pour générer une instruction SQL. Dans ce cas, l'utilisateur peut intégrer des commandes SQL malveillantes, qui seront ensuite envoyées à la base de données pour exécution.
Par exemple, une entrée utilisateur malveillante peut conduire à
SQLString
être égale à"SELECT * FROM CUSTOMERS WHERE NAME='James';DROP TABLE CUSTOMERS;'
En raison de l'utilisateur malveillant,
SQLString
contient 2 déclarations, où la deuxième ("DROP TABLE CUSTOMERS"
) causera des dommages.Déclarations préparées
Dans ce cas, en raison de la séparation de la requête et des données, l'entrée utilisateur n'est jamais traitée comme une instruction SQL et n'est donc jamais exécutée . C'est pour cette raison que tout code SQL malveillant injecté ne causerait aucun dommage. Ainsi, le
"DROP TABLE CUSTOMERS"
ne serait jamais exécuté dans le cas ci-dessus.En un mot, avec des instructions préparées, le code malveillant introduit via l'entrée utilisateur ne sera pas exécuté!
la source
Lorsque vous créez et envoyez une instruction préparée au SGBD, elle est stockée en tant que requête SQL pour exécution.
Vous liez ultérieurement vos données à la requête de telle sorte que le SGBD utilise ces données comme paramètres de requête pour l'exécution (paramétrage). Le SGBD n'utilise pas les données que vous liez comme complément à la requête SQL déjà compilée; ce sont simplement les données.
Cela signifie qu'il est fondamentalement impossible d'effectuer une injection SQL à l'aide d'instructions préparées. La nature même des instructions préparées et leur relation avec le SGBD empêche cela.
la source
Dans SQL Server , l'utilisation d'une instruction préparée est définitivement à l'épreuve des injections car les paramètres d'entrée ne forment pas la requête. Cela signifie que la requête exécutée n'est pas une requête dynamique. Exemple d'instruction vulnérable par injection SQL.
Maintenant, si la valeur de la variable inoutusername est quelque chose comme un 'ou 1 = 1 -, cette requête devient maintenant:
Et le reste est commenté après
--
, donc il n'est jamais exécuté et contourné en utilisant l'exemple d'instruction préparé comme ci-dessous.Donc, en effet, vous ne pouvez pas envoyer un autre paramètre, évitant ainsi l'injection SQL ...
la source
La phrase clé est
need not be correctly escaped
. Cela signifie que vous ne devez pas vous inquiéter des gens qui essaient de lancer des tirets, des apostrophes, des citations, etc.Tout est géré pour vous.
la source
Supposons que vous ayez cela dans un servlet que vous avez raison. Si une personne malveillante passe une mauvaise valeur pour «filtre», vous risquez de pirater votre base de données.
la source
Cause fondamentale n ° 1 - Le problème du délimiteur
L'injection SQL est possible car nous utilisons des guillemets pour délimiter les chaînes et aussi pour faire partie de chaînes, ce qui rend parfois impossible leur interprétation. Si nous avions des délimiteurs qui ne pouvaient pas être utilisés dans les données de chaîne, l'injection SQL ne se serait jamais produite. La résolution du problème du délimiteur élimine le problème d'injection SQL. Les requêtes de structure font cela.
Cause fondamentale n ° 2 - Nature humaine, les gens sont rusés et certains rusés sont malveillants et tous font des erreurs
L'autre cause fondamentale de l'injection SQL est la nature humaine. Les gens, y compris les programmeurs, font des erreurs. Lorsque vous faites une erreur sur une requête structurée, cela ne rend pas votre système vulnérable à l'injection SQL. Si vous n'utilisez pas de requêtes structurées, des erreurs peuvent générer une vulnérabilité d'injection SQL.
Comment les requêtes structurées résolvent les causes profondes de l'injection SQL
Les requêtes structurées résolvent le problème du délimiteur, en mettant des commandes sql dans une instruction et en plaçant les données dans une instruction de programmation distincte. Les instructions de programmation créent la séparation nécessaire.
Les requêtes structurées aident à empêcher l'erreur humaine de créer des failles de sécurité critiques. En ce qui concerne les humains faisant des erreurs, l'injection SQL ne peut pas se produire lorsque des requêtes de structure sont utilisées. Il existe des moyens d'empêcher l'injection SQL qui n'impliquent pas de requêtes structurées, mais une erreur humaine normale dans cette approche conduit généralement à au moins une certaine exposition à l'injection SQL. Les requêtes structurées sont protégées contre les injections SQL. Vous pouvez faire toutes les erreurs du monde, presque, avec des requêtes structurées, comme n'importe quelle autre programmation, mais aucune de ce que vous pouvez faire ne peut être transformée en un ssstem repris par injection SQL. C'est pourquoi les gens aiment dire que c'est la bonne façon d'empêcher l'injection SQL.
Donc, voilà, les causes de l'injection SQL et la nature des requêtes structurées qui les rend impossibles lorsqu'elles sont utilisées.
la source