security prevent - Comment fonctionne l'injection SQL de la BD XKCD "Bobby Tables"?




6 Answers

Il laisse tomber la table des étudiants.

Le code original dans le programme de l'école ressemble probablement à quelque chose comme

q = "INSERT INTO Students VALUES ('" + FNMName.Text + "', '" + LName.Text + "')";

C'est la façon naïve d'ajouter du texte dans une requête, et c'est très mauvais , comme vous le verrez.

Après les valeurs du prénom, la deuxième zone de texte FNMName.Text (qui est Robert'); DROP TABLE STUDENTS; -- Robert'); DROP TABLE STUDENTS; -- Robert'); DROP TABLE STUDENTS; -- ) et le nom de la zone de texte LName.Text (appelons-le Derper ) sont concaténés avec le reste de la requête, le résultat est maintenant en fait deux requêtes séparées par le terminateur d'instruction (point-virgule). La deuxième requête a été injectée dans le premier. Lorsque le code exécute cette requête sur la base de données, il ressemble à ceci

INSERT INTO Students VALUES ('Robert'); DROP TABLE Students; --', 'Derper')

qui, en anglais courant, traduit grossièrement les deux requêtes:

Ajouter un nouvel enregistrement à la table Students avec une valeur Name de 'Robert'

et

Supprimer la table Etudiants

Tout le passé après la deuxième requête est marqué comme un commentaire : --', 'Derper')

Le ' dans le nom de l'étudiant n'est pas un commentaire, c'est le délimiteur de chaîne de fermeture. Étant donné que le nom de l'étudiant est une chaîne, il est nécessaire syntaxiquement de compléter la requête hypothétique. Les attaques par injection ne fonctionnent que lorsque la requête SQL qu'elles injectent aboutit à un SQL valide .

Edité à nouveau selon le commentaire astucieux de dan04

cheat sheet

Juste en regardant:

(Source: https://xkcd.com/327/ )

Que fait ce SQL:

Robert'); DROP TABLE STUDENTS; --

Je sais que les deux sont des commentaires, mais le mot DROP n'est-il pas aussi commenté puisqu'il fait partie de la même ligne?




Comme tout le monde l'a déjà souligné, le '); ferme la déclaration originale, puis une deuxième déclaration suit. La plupart des frameworks, y compris des langages comme PHP, ont maintenant des paramètres de sécurité par défaut qui ne permettent pas plusieurs instructions dans une chaîne SQL. En PHP, par exemple, vous pouvez seulement exécuter plusieurs instructions dans une chaîne SQL en utilisant la fonction mysqli_multi_query .

Vous pouvez cependant manipuler une instruction SQL existante via l'injection SQL sans devoir ajouter une seconde instruction. Disons que vous avez un système de connexion qui vérifie un nom d'utilisateur et un mot de passe avec cette simple sélection:

$query="SELECT * FROM users WHERE username='" . $_REQUEST['user'] . "' and (password='".$_REQUEST['pass']."')";
$result=mysql_query($query);

Si vous fournissez peter comme nom d'utilisateur et secret comme mot de passe, la chaîne SQL résultante ressemblera à ceci:

SELECT * FROM users WHERE username='peter' and (password='secret')

Tout va bien. Imaginez maintenant que vous fournissez cette chaîne comme mot de passe:

' OR '1'='1

Alors la chaîne SQL résultante serait ceci:

SELECT * FROM users WHERE username='peter' and (password='' OR '1'='1')

Cela vous permettrait de vous connecter à n'importe quel compte sans connaître le mot de passe. Vous n'avez donc pas besoin de pouvoir utiliser deux instructions pour utiliser l'injection SQL, bien que vous puissiez faire des choses plus destructrices si vous êtes capable de fournir plusieurs instructions.




TL; DR

-- The application accepts input, in this case 'Nancy', without attempting to
-- sanitize the input, such as by escaping special characters
school=> INSERT INTO students VALUES ('Nancy');
INSERT 0 1

-- SQL injection occurs when input into a database command is manipulated to
-- cause the database server to execute arbitrary SQL
school=> INSERT INTO students VALUES ('Robert'); DROP TABLE students; --');
INSERT 0 1
DROP TABLE

-- The student records are now gone - it could have been even worse!
school=> SELECT * FROM students;
ERROR:  relation "students" does not exist
LINE 1: SELECT * FROM students;
                      ^

Cela laisse tomber la table des étudiants. Pour clarifier ce qui se passe, essayons ceci avec une simple table contenant seulement le champ name et ajoutons une seule ligne (testée avec PostgreSQL 9.1.2):

school=> CREATE TABLE students (name TEXT PRIMARY KEY);
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "students_pkey" for table "students"
CREATE TABLE
school=> INSERT INTO students VALUES ('John');
INSERT 0 1

Supposons que l'application utilise le code SQL suivant pour insérer des données dans la table:

INSERT INTO students VALUES ('foobar');

Remplacez foobar par le nom réel de l'étudiant. Une opération d'insertion normale ressemblerait à ceci:

--                            Input:   Nancy
school=> INSERT INTO students VALUES ('Nancy');
INSERT 0 1

Lorsque nous interrogeons la table, nous obtenons ceci:

school=> SELECT * FROM students;
 name
-------
 John
 Nancy
(2 rows)

Que se passe-t-il lorsque nous insérons le nom de Little Bobby Tables dans la table?

--                            Input:   Robert'); DROP TABLE students; --
school=> INSERT INTO students VALUES ('Robert'); DROP TABLE students; --');
INSERT 0 1
DROP TABLE

L'injection SQL est ici le résultat du nom de l'étudiant terminant l'instruction et incluant une commande DROP TABLE séparée; les deux tirets à la fin de l'entrée sont destinés à commenter tout code restant qui provoquerait sinon une erreur. La dernière ligne de la sortie confirme que le serveur de base de données a supprimé la table.

Il est important de noter que pendant l'opération INSERT , l'application ne vérifie pas l'entrée des caractères spéciaux, et permet donc de saisir une entrée arbitraire dans la commande SQL. Cela signifie qu'un utilisateur malveillant peut insérer, dans un champ normalement destiné à l'entrée de l'utilisateur, des symboles spéciaux tels que des guillemets ainsi que du code SQL arbitraire pour que le système de base de données l'exécute, d'où SQL "injection" .

Le résultat?

school=> SELECT * FROM students;
ERROR:  relation "students" does not exist
LINE 1: SELECT * FROM students;
                      ^

L'injection SQL est l'équivalent de la base de données d'une vulnérabilité d' exécution de code arbitraire à distance dans un système d'exploitation ou une application. L'impact potentiel d'une attaque par injection SQL réussie ne peut pas être sous-estimé - selon le système de base de données et la configuration de l'application, il peut être utilisé par un attaquant pour provoquer une perte de données (comme dans le cas présent) code arbitraire sur la machine hôte elle-même.

Comme indiqué par la bande dessinée XKCD, une protection contre les attaques par injection SQL consiste à désinfecter les entrées de la base de données, par exemple en échappant aux caractères spéciaux, afin qu'elles ne puissent pas modifier la commande SQL sous-jacente et ne puissent pas exécuter de code SQL arbitraire. Si vous utilisez des requêtes paramétrées, par exemple en utilisant SqlParameter dans ADO.NET, l'entrée sera automatiquement nettoyée pour vous.




Une seule citation est le début et la fin d'une chaîne. Un point-virgule est la fin d'une déclaration. Donc, s'ils faisaient une sélection comme ceci:

Select *
From Students
Where (Name = '<NameGetsInsertedHere>')

Le SQL deviendrait:

Select *
From Students
Where (Name = 'Robert'); DROP TABLE STUDENTS; --')
--             ^-------------------------------^

Sur certains systèmes, le select serait exécuté en premier suivi de l'instruction drop ! Le message est le suivant: NE PAS INTRODUIRE DES VALEURS DANS VOTRE SQL. Au lieu d'utiliser des paramètres!




L'auteur de la base de données a probablement fait un

sql = "SELECT * FROM STUDENTS WHERE (STUDENT_NAME = '" + student_name + "') AND other stuff";
execute(sql);

Si student_name est celui donné, cela fait la sélection avec le nom "Robert" et ensuite abandonne la table. La partie "-" change le reste de la requête donnée en commentaire.




Le caractère ' dans SQL est utilisé pour les constantes de chaîne. Dans ce cas, il est utilisé pour terminer la chaîne de caractères et non pour commenter.




Related

security validation sql-injection