Injection SQL
Un article de Wikipédia, l'encyclopédie libre.
Cet article est une ébauche concernant la sécurité informatique.
Vous pouvez partager vos connaissances en l’améliorant. (Comment ?).
|
Une injection SQL est un type d'exploitation d'une faille de sécurité d'une application web, en injectant une requête SQL non prévue par le système et pouvant compromettre sa sécurité.
Sommaire |
[modifier] Exemple
Considérons un site web dynamique (programmé par exemple en PHP) qui dispose d'un système permettant aux utilisateurs possédant un nom d'utilisateur et un mot de passe valides de se connecter. Ce site utilise la requête SQL suivante pour identifier un utilisateur :
SELECT uid WHERE name = '(nom)' AND password = '(mot de passe chiffré)'
L'utilisateur Dupont souhaite se connecter avec son mot de passe "truc" encodé en MD5. La requête suivante est exécutée :
SELECT uid WHERE name = 'Dupont' AND password = '45723a2af3788c4ff17f8d1114760e62'
[modifier] Attaquer la requête
Imaginons à présent que le script PHP exécutant cette requête ne vérifie pas les données entrantes pour garantir sa sécurité. Un pirate informatique pourrait alors fournir les informations suivantes :
- Utilisateur :
Dupont' --
- Mot de passe : n'importe lequel
La requête devient :
SELECT uid WHERE name = 'Dupont' -- ' AND password = '4e383a1918b432a9bb7702f086c56596e'
Les caractères --
marquent le début d'un commentaire en SQL. La requête est donc équivalente à :
SELECT uid WHERE name = 'Dupont'
Le pirate peut alors se connecter sous l'utilisateur Dupont avec n'importe quel mot de passe. Il s'agit d'une injection de SQL réussie, car le pirate est parvenu à injecter les caractères qu'il voulait pour modifier le comportement de la requête.
[modifier] Solution
Ici, la solution consiste à traiter correctement les chaînes de caractères entrées par l'utilisateur.
En PHP on peut utiliser pour cela la fonction mysql_real_escape_string
, qui transformera la chaîne ' --
en \' --
. La requête deviendrait alors :
SELECT uid WHERE name = 'Dupont\' -- ' AND password = '4e383a1918b432a9bb7702f086c56596e'
L'apostrophe de fin de chaîne ayant été correctement dé-spécialisée en la faisant précéder d'un caractère «\».
L'échappement peut aussi se faire (suivant le SGBD utilisé) en doublant les apostrophes.
La marque de commentaire fera alors partie de la chaîne, et finalement le serveur SQL répondra qu'il n'y a aucune entrée dans la base de données correspondant à l'utilisateur Dupont' --
.
La fonction addslashes
ne suffit pas pour stopper les injections via les variables numériques, qui ne sont pas encadrées d'apostrophes ou de guillemets dans les requêtes SQL. Exemple avec la requête :
SELECT ... FROM ... WHERE numero_badge = $numero AND code_4_chiffre = $code
qui réussit lorsque la variable $numero
contient 0 or 1=1 --
. Une précaution est d'utiliser la fonction is_numeric
pour vérifier les variables numériques des requêtes. On peut aussi forcer la transformation de la variable en nombre en la faisant précéder d'un transtypeur, comme (int)
si on attend un entier (la chaîne 0 or 1=1 --
sera alors transformée en l'entier 0
et l'injection SQL échouera).
La fonction addslashes
possède elle-même quelques failles sur certaines versions de PHP qui datent. De plus, elle échappe uniquement les caractères «'» et «"». Il serait plus approprié d'utiliser la fonction mysql_real_escape_string qui est justement créée pour échapper les caractères spéciaux d'une commande SQL (NULL, \x1a, \n, \r, \, ', " et \x00).
[modifier] Comment éviter ces attaques
Ces attaques peuvent être évités de plusieurs façons :
- Utiliser des procédures stockées, à la place du SQL dynamique. Les données entrées par l'utilisateur sont alors transmises comme paramètres, sans risque d'injection.
- Vérifier de manière précise et exhaustive l'ensemble des données venant de l'utilisateur. On peut, par exemple, utiliser une expression rationnelle afin de valider qu'une donnée entrée par l'utilisateur est bien de la forme souhaitée.
- Utiliser des comptes utilisateurs SQL à accès limité (en lecture-seule) quand cela est possible.
- Activer les protections internes comme l'option magic_quotes_gpc en PHP.
- Utiliser des requêtes SQL préparées (requêtes à trous envoyées au serveur SQL, serveur à qui l'on envoie par la suite les paramètres qui boucheront les trous), ainsi c'est le SGBD qui se charge d'échapper les caractères selon le type des paramètres.
Note : Pour contrer les injections de code SQL, les "magic quotes" sont utilisées par défaut dans la configuration de PHP. Elles permettent de placer un caractère d’échappement devant les apostrophes. Certaines faille de sécurité, comme le fait de ne pas s’appliquer sur les champs hidden des formulaires, et l’annonce de la disparition de magic_quotes_gpc dans PHP6 nous incite à remplacer cette option par l’usage systématique de la fonction addslashes().
[modifier] Voir aussi
[modifier] Liens externes
- (fr) Éviter les injections SQL avec PHP
- (fr) Les bases des injections SQL : Comment les repérer, les exploiter, les corriger
- (fr) Les injections SQL en aveugle (Blind SQL Injections)
- (en) MS Access SQL Injection Cheat Sheet
- (en) Illustration d'une attaque SQL (dessin)