une - requete préparée injection sql




Comment les instructions préparées peuvent-elles protéger contre les attaques par injection SQL? (6)

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'une instruction SQL d'injection vulnérable.

string sqlquery = "select * from table where username='" + inputusername +"' and password='" + pass + "'";

Maintenant, si la valeur de la variable inoutusername est quelque chose comme 'ou 1 = 1 -, cette requête devient:

select * from table where username='a' or 1=1 -- and password=asda

Et le reste est commenté après, de sorte qu'il ne soit jamais exécuté et contourné en utilisant l'exemple d'instruction préparée comme ci-dessous.

Sqlcommand command = new sqlcommand("select * from table where username = @userinput and [email protected]");
command.Parameters.Add(new SqlParameter("@userinput", 100));
command.Parameters.Add(new SqlParameter("@pass", 100));
command.prepare();

Donc, en effet, vous ne pouvez pas envoyer un autre paramètre, évitant ainsi l'injection SQL ...

Comment les instructions préparées nous aident-elles à prévenir les attaques par injection SQL ?

Wikipedia dit:

Les instructions préparées sont résilientes contre l'injection SQL, car les valeurs de paramètres, transmises ultérieurement à l'aide d'un protocole différent, n'ont pas besoin d'être correctement échappées. Si le modèle d'instruction d'origine n'est pas dérivé d'une entrée externe, l'injection SQL ne peut pas avoir lieu.

Je ne vois pas très bien la raison. Quelle serait une explication simple en anglais facile et quelques exemples?


Fondamentalement, avec les instructions préparées, les données provenant d'un pirate potentiel sont traitées comme des données - et il est impossible de les mélanger avec votre application SQL et / ou d'être interprétées comme SQL (ce qui peut arriver lorsque les données sont directement placées dans votre application). application SQL).

Cela est dû au fait que les instructions préparées "préparent" la requête SQL en premier pour trouver un plan de requête efficace et envoient les valeurs réelles qui proviennent vraisemblablement d'un formulaire ultérieurement - à ce moment la requête est réellement exécutée.

Plus d'informations utiles ici:

Instructions préparées et injection SQL


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 est le mélange du code et des données.

En fait, notre requête SQL est un programme légitime . Et nous créons dynamiquement un tel programme, en ajoutant quelques données à la volée. Ainsi, ces 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 dans 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

alors 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, donc les données peuvent altérer le programme et selon les données transmises, nous aurons soit une sortie normale, soit une table supprimée par les users .

Alors que dans le cas de déclarations préparées, nous ne modifions pas notre programme, il reste intact
C'est le but.

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 un espace réservé.

Notez que la même requête est envoyée au serveur, sans aucune donnée dedans! Et puis nous envoyons les données avec la deuxième requête, essentiellement séparées de la requête elle-même:

$db->execute($data);

donc, il ne peut pas modifier notre programme et faire du mal.
Assez simple - n'est-ce pas?

Cependant, il vaut la peine de noter que pas chaque fois que vous utilisez un espace réservé, il est traité comme une déclaration préparée .

Un espace réservé est une idée générale pour substituer les données réelles avec une variable pour le traitement futur (voir printf() par exemple), tandis qu'une instruction préparée est le seul sous-ensemble de celle-ci.

Il y a des cas (notamment le PDO en PHP peut le faire) quand une instruction préparée peut être émulée, et une requête est réellement composée avec des données et envoyée au serveur dans une requête. Mais il est important de comprendre que cette approche est tout aussi sûre , car chaque bit de données est correctement formaté en fonction de son type et donc rien de mal pourrait se produire.

La seule chose que j'ai à ajouter est toujours omis dans chaque manuel:

Les instructions préparées peuvent protéger uniquement les données , mais ne peuvent pas défendre le programme lui-même .
Ainsi, une fois que nous devons ajouter, disons, un identifiant dynamique - un nom de champ, par exemple, les déclarations préparées ne peuvent pas nous aider. J'ai expliqué la question récemment , donc je ne vais pas me répéter.


La phrase clé 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.


Voici SQL pour configurer un exemple:

CREATE TABLE employee(name varchar, paymentType varchar, amount bigint);

INSERT INTO employee VALUES('Aaron', 'salary', 100);
INSERT INTO employee VALUES('Aaron', 'bonus', 50);
INSERT INTO employee VALUES('Bob', 'salary', 50);
INSERT INTO employee VALUES('Bob', 'bonus', 0);

La classe Inject est vulnérable à l'injection SQL. La requête est collée dynamiquement avec l'entrée de l'utilisateur. L'objectif de la requête était de montrer des informations sur Bob. Soit un salaire ou un bonus, basé sur l'entrée de l'utilisateur. Mais l'utilisateur malveillant manipule l'entrée corrompant la requête en virant sur l'équivalent d'un 'ou vrai' à la clause where pour que tout soit retourné, y compris les informations sur Aaron qui était censé être caché.

import java.sql.*;

public class Inject {

    public static void main(String[] args) throws SQLException {

        String url = "jdbc:postgresql://localhost/postgres?user=user&password=pwd";
        Connection conn = DriverManager.getConnection(url);

        Statement stmt = conn.createStatement();
        String sql = "SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType='" + args[0] + "'";
        System.out.println(sql);
        ResultSet rs = stmt.executeQuery(sql);

        while (rs.next()) {
            System.out.println(rs.getString("paymentType") + " " + rs.getLong("amount"));
        }
    }
}

En cours d'exécution, le premier cas est avec une utilisation normale, et le second avec l'injection malveillante:

c:\temp>java Inject salary
SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType='salary'
salary 50

c:\temp>java Inject "salary' OR 'a'!='b"
SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType='salary' OR 'a'!='b'
salary 100
bonus 50
salary 50
bonus 0

Vous ne devez pas générer vos instructions SQL avec la concaténation de chaîne de l'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 cache d'instruction SQL alors que l'exemple de liaison exécute toujours la même instruction).

Voici un exemple de liaison pour éviter ce type d'injection:

import java.sql.*;

public class Bind {

    public static void main(String[] args) throws SQLException {

        String url = "jdbc:postgresql://localhost/postgres?user=postgres&password=postgres";
        Connection conn = DriverManager.getConnection(url);

        String sql = "SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType=?";
        System.out.println(sql);

        PreparedStatement stmt = conn.prepareStatement(sql);
        stmt.setString(1, args[0]);

        ResultSet rs = stmt.executeQuery();

        while (rs.next()) {
            System.out.println(rs.getString("paymentType") + " " + rs.getLong("amount"));
        }
    }
}

En cours d'exécution avec la même entrée que l'exemple précédent, le code malveillant ne fonctionne pas car aucun type de paiement ne correspond à cette chaîne:

c:\temp>java Bind salary
SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType=?
salary 50

c:\temp>java Bind "salary' OR 'a'!='b"
SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType=?

Cause racine # 1 - Le problème du délimiteur

L'injection Sql est possible car nous utilisons des guillemets pour délimiter des 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 n'aurait jamais eu lieu. La résolution du problème de délimitation élimine le problème d'injection SQL. Les requêtes de structure le font.

Cause racine n ° 2 - La nature humaine, les gens sont rusés et certaines personnes astucieuses sont malveillantes et tous les gens font des erreurs

L'autre cause de l'injection de 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, votre système n'est pas 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

Requêtes structurées Résolvez le problème du délimiteur en plaçant les 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 les erreurs humaines 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 les requêtes de structure sont utilisées. Il existe des moyens de prévenir l'injection SQL qui n'impliquent pas de requêtes structurées, mais l'erreur humaine normale dans ces approches conduit généralement à au moins une certaine exposition à l'injection sql. Les requêtes structurées sont à l'abri de l'injection SQL. Vous pouvez faire toutes les erreurs dans le monde, presque, avec des requêtes structurées, comme n'importe quelle autre programmation, mais aucune de celles que vous pouvez faire peut être transformée en un système pris en charge par l'injection sql. C'est pourquoi les gens aiment à dire que c'est la bonne façon d'éviter l'injection SQL.

Donc, là vous l'avez, les causes de l'injection sql et les requêtes structurées de nature qui les rend impossible quand ils sont utilisés.





prepared-statement