Injection SQL

SQL injection

Injection SQL, qu’est-ce que c’est?

Tout d’abord, voyons ce que signifie le terme SQL. SQL (Structured Query Language) est un langage structuré standardisé de manipulation des bases de données qui sont utilisées par tous les sites dynamiques. À titre d’exemple, lorsqu’on émet la requête de consulter un article, le serveur va construire la page demandée à l’aide des informations contenues dans la base de données.

Les techniques d’injection SQL consistent donc à introduire du code dans une requête SQL pour récupérer des données de manière illégitime ou pour prendre le contrôle du système. Cette vulnérabilité concerne toutes les applications utilisant une base SQL.

Principe de base

Je propose d’utiliser une requête de base qui permet d’authentifier un utilisateur dans une application web :

SELECT login FROM users WHERE login ='aidenkers' AND password = 'sesame'

En clair, cette requête demande la donnée « login » de la table « users » dont la condition est que le login = « aidenkers » et que le password = « sesame ».

Les techniques d’injection SQL consistent à manipuler les entrées attendues par l’application (ici login et password) de façon non prévue.

Cas des formulaires d’authentification

SQL_injection

Ici, nous allons démontrer plusieurs méthodes pour s’authentifier avec un compte qui ne nous appartient pas. Cela pourrait compromettre la sécurité d’un site, par exemple si l’on arrive à s’authentifier sur le compte d’un administrateur.

– La requête suivante permet de vérifier le mot de passe et le login d’un utilisateur :

$query = '' SELECT login, password FROM utilisateurs WHERE login = '$_POST['login']' AND password ='$_POST['password']' ''

→ Utilisons comme entrée « login » a’ OR ‘a’=’a et « password » a’ OR ‘a’=’a

$query = ''SELECT login, password FROM users WHERE login = "a' OR 'a' = 'a' AND password = "a' OR 'a'='a'

Résultat : Syntaxiquement, la requête est bien construite et elle nous permet de passer le formulaire. En effet, la condition ‘a’=’a’ nous renverra toujours la valeur « vrai » !

– Maintenant, supposons que nous connaissons le login de l’administrateur mais pas son mot de passe.

→ Utilisons comme entrée ‘administrateur’ /*

$query = ''SELECT login, password FROM users WHERE login = 'administrateur' /* AND password ='' ''

Résultat : Le /* permet en SQL de marquer le début d’un commentaire. Ce qui le suit n’est pas vu comme une instruction, donc la suite de la requête n’est pas prise en compte et l’utilisateur sera authentifié avec le compte ayant pour login administrateur.

– Le cas précédent suppose que nous connaissions le login. Mais comment valider le login sans connaître de nom?

→ Utilisons une condition qui est toujours vraie : ‘ or 1=1 /*

$query = ''SELECT login, password FROM users WHERE login = ' ' OR 1=1 /* AND password ='' ''

Résultat : Nous arrivons à valider le nom avec 1=1 qui renvoie toujours « vrai » et nous utilisons /* pour ignorer le mot de passe.

Exploitation des messages d’erreurs

Les messages d’erreurs permettent de faciliter l’exploitation d’une faille. En d’autres termes, nous pouvons faire « parler » la table de données pour récupérer des informations afin de connaître l’architecture d’une table pour mieux la manipuler et d’atteindre les informations qui semblent avoir le plus de valeur.

– Utilisation du mot clé GROUP BY

→ Lors de nos exemples, on a demandé l’affichage des colonnes « login » et « password ». Maintenant nous voulons savoir si la table « users » contient d’autres colonnes. Pour cela, utilisons ‘HAVING 1=1 /*

$query = ''SELECT login, password FROM users WHERE login = ' ' HAVING 1=1 /* AND password ='' ''

Résultat : Le serveur va alors nous retourner un message d’erreur de type : « Column users.id is invalid ……. » Ce message nous permet d’apprendre que la table « users » contient comme première colonne « id »

→ Maintenant, formulons la requête suivante : ‘GROUP BY users.id HAVING 1=1 /*

$query = ''SELECT login, password FROM users WHERE login = ' ' GROUP BY users.id HAVING 1=1 /* AND password ='' ''

Résultat : Le serveur va de nouveau nous retourner un message d’erreur de type : « Column users.login is invalid…. ». Nous savons que le second champ est « login »

→ On lance une autre requête avec le nom de la colonne trouvé (‘GROUP BY users.id, login HAVING 1=1 /* ), et ainsi de suite jusqu’à avoir toutes les colonnes de la table.

Changer des valeurs :

Lorsque que l’on s’inscrit sur un site, une requête d’insertion de données est envoyée au serveur. Cette requête est du type suivant :

$query = '' INSERT INTO users VALUES ('', '$login', '$password' , '$mail', 1)''

le 1 indique le privilège. (1000 étant celui d’administrateur)

→ Imaginons que l’utilisateur entre dans le champ « mail » : test@test.com ‘ , 1000 /*

$query = '' INSERT INTO users VALUES ('', '$login', '$password' , '$mail',1000 /* , 1)''

Résultat : L’utilisateur obtient les droits d’administrateur dés son inscription!

Injection SQL à l’aveugle :

Une erreur ne provoquant pas toujours de réaction identifiable, cherchons à rentrer de l’information que l’on veut valider dans la requête.
– Versions du serveur.
→ Utilisons a’ OR @@version > 3;

SELECT * FROM table WHERE champ = 'a' OR @@version >3 ;

Résultat : Si la requête renvoie une erreur, cela signifie que la version est inférieure à 3. Sinon, que la version est supérieure à 3.

Comment protéger sa base de données :

  • Ne jamais faire confiance à l’utilisateur.
  • Désactiver les fonctions non utilisées : il est important de désactiver toutes les fonctions que vous n’utilisez pas afin de réduire le champ d’action des failles.
  • Messages d’erreurs personnalisés : dans la mesure où les messages d’erreurs SQL donnent trop d’informations aux utilisateurs, il est fortement conseillé de les personnaliser.
  • Fonctions d’échappement : les fonctions d’échappement sont très facile à mettre en œuvre et permettent de sécuriser efficacement le serveur contre la plupart des injections.
  • Interdire certains mots clés : notamment les mots clés ou caractères spéciaux de type interprétable.
  • Utiliser les Prepare Statements : Cette solution reste la plus efficace contre les injections. Toutefois, elle demande beaucoup de temps mais elle a une dimension de sécurité dont nous ne devons pas nous passer.

© Photo par: Casey Bisson sur : flickr

Related Posts

Comments are closed.