Aller au contenu

Injection SQL

Un article de Wikipédia, l'encyclopédie libre.
Ceci est une version archivée de cette page, en date du 15 septembre 2016 à 17:02 et modifiée en dernier par 84.14.214.215 (discuter) (J'ai changé "bind" based en "blind" based, car c'est de ce type d'injection dont il s'agit, dont la cousine est effectivement la time based). Elle peut contenir des erreurs, des inexactitudes ou des contenus vandalisés non présents dans la version actuelle.

La faille SQLi, abréviation de "SQL Injection", soit "injection SQL" en français, est un groupe de méthodes d'exploitation de faille de sécurité d'une application interagissant avec une base de données. Elle permet d'injecter dans la requête SQL en cours un morceau de requête non prévu par le système et pouvant en compromettre la sécurité.

Il existe plusieurs types d'injection SQL :

La méthode "blind based" (associée à sa cousine la "time based" au fonctionnement relativement identique), qui permet de détourner la requête SQL en cours sur le système et d'injecter des morceaux qui vont retourner caractère par caractère ce que l'attaquant cherche à extraire de la base de données. La méthode bind based, ainsi que la time based, se basent sur la réponse du serveur : si la requête d'origine renvoie bien le même résultat qu'à l'origine (et indique donc que le caractère est valide) ou ne renvoie pas le même résultat (et indique donc que le caractère testé n'est pas le bon). La time based a pour seule différence qu'elle se base sur le temps de réponse du serveur plutôt que sur la réponse en elle-même.

La méthode "error based", qui permet de détourner la requête SQL en cours sur le système et d'injecter des morceaux qui vont retourner champ par champ ce que l'on cherche à extraire de la base de données. Cette méthode profite d'une faiblesse des systèmes de base de données permettant de détourner un message d'erreur généré par le système de base de données et préalablement volontairement provoquée par l'injection SQL pour lui faire retourner une valeur précise récupérée en base de données.

La méthode "union based", qui permet de détourner la requête SQL en cours sur le système et d'injecter des morceaux qui vont retourner un ensemble de données directement extraites de la base de données. Cette méthode profite de certaines méthodes afin de détourner entièrement le retour de la requête SQL d'origine afin de lui faire retourner en une seule requête un important volume de données, directement récupéré en base de données. Dans ses exemples les plus violents, il est possible de récupérer des tables entières de base de données en une ou deux requêtes, même si en général cette méthode retourne entre 10 et 100 lignes de la base de données par requête SQL détournée.

Et enfin, la méthode "Stacked queries", la plus dangereuse de toute. Profitant d'une erreur de configuration du serveur de base de données, cette méthode permet d'exécuter n'importe quelle requête SQL sur le système impacté, ce qui ne se limite pas seulement à récupérer des données comme les 3 précédentes. En effet, quand ce type de requête n'est pas désactivé, il suffit d'injecter une autre requête SQL, et elle sera exécutée sans problème, qu'elle aille chercher des données, ou en modifier directement dans la base de données.

Exemple

Considérons un site web dynamique (programmé en PHP dans cet exemple) 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 FROM Users WHERE name = '(nom)' AND password = '(mot de passe hashé)';

L'utilisateur Dupont souhaite se connecter avec son mot de passe « truc » hashé en MD5. La requête suivante est exécutée :

SELECT uid FROM Users WHERE name = 'Dupont' AND password = '45723a2af3788c4ff17f8d1114760e62';

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 hacker pourrait alors fournir les informations suivantes :

  • Utilisateur : Dupont';--
  • Mot de passe : n'importe lequel

La requête devient :

SELECT uid FROM Users 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 FROM Users WHERE name = 'Dupont';

L'attaquant 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 l'attaquant est parvenu à injecter les caractères qu'il voulait pour modifier le comportement de la requête.

Supposons maintenant que l'attaquant veuille non pas tromper le script SQL sur le nom d'utilisateur, mais sur le mot de passe. Il pourra alors injecter le code suivant :

  • Utilisateur : Dupont
  • Mot de passe : ' or 1 --

L'apostrophe indique la fin de la zone de frappe de l'utilisateur, le code « or 1 » demande au script si 1 est vrai, or c'est toujours le cas, et -- indique le début d'un commentaire.

La requête devient alors :

SELECT uid FROM Users WHERE name = 'Dupont' AND password = '' or 1 --';

Ainsi, le script programmé pour vérifier si ce que l'utilisateur tape est vrai, il verra que 1 est vrai, et l'attaquant sera connecté sous la session Dupont.

Solutions

Échappement des caractères spéciaux

La première solution consiste à échapper les caractères spéciaux contenus dans les chaînes de caractères entrées par l'utilisateur.

En PHP on peut utiliser pour cela la fonction mysqli_real_escape_string, qui transformera la chaîne ' -- en \' --. La requête deviendrait alors  :

SELECT uid FROM Users 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 à un utilisateur Dupont' -- avec ce mot de passe.

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 --. Une précaution est d'utiliser la fonction ctype_digit 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 -- 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 « \ », « NULL », « ' » et « " ». Il serait plus approprié d'utiliser la fonction mysqli_real_escape_string qui échappe justement les caractères spéciaux d'une commande SQL (NULL, \x1a, \n , \r , \, ', " et \x00).

Utilisation d'une requête préparée

La seconde solution consiste à utiliser des requêtes préparées : dans ce cas, une compilation de la requête est réalisée avant d'y insérer les paramètres et de l'exécuter, ce qui empêche un éventuel code inséré dans les paramètres d'être interprété.

Comment éviter ces attaques

Ces attaques peuvent être évitées de plusieurs façons :

  1. 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, qui, s'ils sont correctement utilisés par la procédure (par exemple injectés dans une requête paramétrée), évitent l'injection ;
  2. 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, ou profiter de fonctions de transformation spécifiques au langage ;
  3. Utiliser des comptes utilisateurs SQL à accès limité (en lecture-seule) quand cela est possible ;
  4. Utiliser des requêtes SQL paramétré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.

En PHP

Les « magic quotes » étaient utilisées par défaut dans la configuration de PHP. Elles permettaient qu'un caractère d’échappement soit automatiquement placé devant les apostrophes et guillemets dangereux.

Certaines failles de sécurité et la disparition de magic_quotes_gpc dans PHP5.4 incitent à remplacer cette option par les solutions ci-dessus : la fonction mysqli_real_escape_string, les classes PHP Data Objectsetc.

Exemples

  • En février 2002, Jeremiah Jacks révèle une faille de sécurité sur le site de Guess.com exploitable par une attaque d’injection SQL et permettant d’obtenir les coordonnées de plus de 200,000 personnes y compris leurs numéros de cartes de crédit avec la date d’expiration[1].
  • Le 1er novembre 2005, un jeune pirate utilise l’injection SQL pour s’introduire dans le site d’information taïwanais consacrée à la sécurité informatique et s’empare des données de la base client[2].
  • Le 29 mars 2006, un pirate s’attaque par une injection SQL au site officiel du tourisme indien appartenant au gouvernement[3].
  • En janvier 2008, des dizaines de milliers de PC sont infectées par une injection SQL automatique exploitant une faille de sécurité de Microsoft SQL Server.
  • Le 13 avril 2008 survient le vol de 10 597 numéros de sécurité sociale américains[4].
  • Le 17 août 2009, le département de la justice américaine identifie l'américain Albert Gonzales et deux russes comme les auteurs du vol de 130 millions de numéros de cartes de crédit grâce à une attaque par injection SQL. Les principales victimes sont la société de traitement des paiements par cartes Hearland Payment Systems, les chaînes de supermarché 7-eleven et Hannaford Brothers[5].
  • Le 24 juillet 2010, des attaques par injection SQL simultanées de Japon et de Chine parviennent à pénétrer la société NeoBeat qui gère des supermarchés sur internet et volent 12 191 données de cartes bancaires.
  • Le 8 novembre 2010, un pirate roumain appelé TinKode utilise une attaque par injection SQL pour paralyser le site de la Royal Navy en Angleterre[6],[7].
  • Le 11 avril 2011, l’ensemble du réseau Barracuda est victime d’une attaque par injection SQL. Identifiants et adresses emails des employés sont détournés[8].
  • Le 1er juin 2011, le groupe appelé LulzSec est accusé d’une attaque par injection SQL contre le site de Sony. Au moins 1 million de clients se font voler coupons, clés d’activation et mot de passe[9],[10].
  • En juillet 2012, Yahoo rapporte le vol de données de plus de 450,000 clients[11],[12][réf. incomplète].

Notes et références

  1. (en) « Guesswork Plagues Web Hole Reporting », SecurityFocus, .
  2. (en) « WHID 2005-46: Teen uses SQL injection to break to a security magazine web site », Web Application Security Consortium, (consulté le ).
  3. (en) « WHID 2006-27: SQL Injection in incredibleindia.org », Web Application Security Consortium, (consulté le ).
  4. (en) Alex Papadimoulis, « Oklahoma Leaks Tens of Thousands of Social Security Numbers, Other Sensitive Data », The Daily WTF, (consulté le ).
  5. (en) « US man 'stole 130m card numbers' », BBC, (consulté le ).
  6. (en) Royal Navy website attacked by Romanian hacker, BBC News, 8-11-10[Quand ?], Accessed November 2010.
  7. (en) Sam Kiley, « Super Virus A Target For Cyber Terrorists », (consulté le ).
  8. (en) « Hacker breaks into Barracuda Networks database ».
  9. (en) « LulzSec hacks Sony Pictures, reveals 1m passwords unguarded », electronista.com, .
  10. (en) Ridge Shan, « LulzSec Hacker Arrested, Group Leaks Sony Database », The Epoch Times, .
  11. (en) Chenda Ngak. "Yahoo reportedly hacked: Is your account safe?", CBS News. 12 juillet 2012. Consulté le 16 juillet 2012.
  12. http://www.zdnet.com/450000-user-passwords-leaked-in-yahoo-breach-7000000772/

Voir aussi

Articles connexes

Liens externes