Défiguration, vol et/ou corruption de données, propagation de codes malveillants, XSS ... L'injection SQL est devenue en quelques mois la bête noire des administrateurs. Comment les pirates opèrent-ils et que faut-il faire pour se protéger ?
Une grande majorité des sites Web a recours à une base de données pour y stocker la structure du site, le contenu des pages et les informations confidentielles des utilisateurs. Les codes des pages Web se contentent d’interroger les bases de données et de mettre en forme les informations retournées pour les présenter aux internautes. Les bases contiennent à l’évidence des informations sensibles que personne ne laisserait consciemment en libre accès sur Internet. Le fait que les accès se fassent par l’intermédiaire de fichiers donne un faux sentiment de cloisonnement et de sécurité. Or, il est en fait relativement facile d’interagir plus ou moins directement à distance avec les bases de données, en exploitant des faiblesses de développement des pages servant d’interfaces avec Internet.
Revenons dans un premier temps sur le fonctionnement global de serveurs Web reposant sur une base de données.
Mode de fonctionnement normal
Dans le cas d’un fonctionnement courant, la visualisation d’une page Web, sur un site utilisant une base de données, se fait en quatre étapes :
- Les paramètres qualifiant la requête HTTP sont envoyés à une page du serveur. Ces paramètres peuvent être explicitement demandés à l’internaute par l’intermédiaire de formulaires ou être implicites dans des liens. Par exemple, un lien direct pour accéder à la section information d’un site pourrait être :
« Page d’informations » . Dans ce cas, le paramètre et sa valeur sont implicites (paramètre= « page », valeur= « info»). - Les paramètres reçus sont utilisés pour construire une requête SQL (Structured Query Language ou langage de requête structuré) interprétée par la base. Par exemple, la valeur du paramètre page est utilisée dans la requête SQL suivante [1] :
« SELECT titre_page,contenu_page FROM table_page WHERE nom=page ». Ici, la variable page vaut info ». - La base de données traite la requête SQL et retourne les données trouvées. A ce niveau là, dans la majorité des cas, aucun traitement ni vérification ne sont faits, si ce n’est ceux liés à la structure de la base et gérés automatiquement par le moteur interne. Exemple : l’utilisateur (le serveur Web) doit avoir le droit d’accéder aux données.
- Le code du site qui est à l’origine de la requête récupère les données pour la mise en page et les envoie en réponse (HTTP). Par exemple, la page index.php récupère les informations titre_page et contenu_page et retourne le tout.
Dans ces conditions, comment opère une attaque par injection SQL ?
Attaque par injection
Au cours d’une tentative d’intrusion par injection SQL, le déroulement suit les même quatre étapes. Mais l’attaquant va influer sur le comportement de la base en modifiant les paramètres envoyés au serveur. Dans l’exemple suivant, le contenu de la page d’information est modifié en insérant un cadre HTML (iframe) pointant vers www.google.fr.
- La première étape consiste à tester des valeurs du paramètre page, le but étant in fine de faire exécuter des commandes illégitimes à la base de données. Il peut s’agir de :
‘info; update table_page set contenu_page= » - Le code de la page récupérant cette valeur construit la requête en remplaçant le paramètre par sa valeur. Cela donne : « SELECT titre_page,contenu_page FROM table_page WHERE nom=info; UPDATE table_page SET contenu_page= »
- La base reçoit une commande contenant deux requêtes séparées par un point virgule. Elle les exécute donc l’une après l’autre. La première est normale. La seconde « UPDATE» le champ page_contenu dans la table table_page pour la ligne identifiée par le nom info. Le champ est remplacé par le texte «
- La réponse envoyée au navigateur reste la même.
À ce niveau le contenu des informations de la base de données a été compromis. Le page d’information a été changée et les navigateurs des internautes chargeront un cadre contenant la page de www.google.fr en lieu et place des informations légitimes. Ce cadre aurait tout aussi bien pu pointer vers une page contenant du code malveillant.
Les injections SQL massives : un phénomène en recrudescence
Depuis le début de l’année 2008, on assiste à une recrudescence d’attaques massives par injection SQL, dont la presse spécialisée s’est faite l’écho. Ces attaques reposent sur deux processus permettant de compromettre la quasi intégralité des données au sein de nombreux sites. La première passe par l’utilisation d’outils qui interrogent les moteurs de recherche populaires pour trouver des adresses de pages indexées contenant une chaîne de caractères caractéristique d’une vulnérabilité. (exemple pour un composant Joomla! en juillet 2008 : index.php?option=com_n-forms&form_id=). L’attaquant n’a qu’à préciser la faille à utiliser et le texte à insérer pour que l’outil compromette un maximum de sites.
L’autre est au niveau de la requête SQL. Plutôt que de viser nominativement des champs d’une table, ce qui nécessite de connaître la structure de la base, il est possible de cibler un type de données. Au niveau de la requête, l’attaquant va modifier tous les champs texte de toutes les tables de toutes les bases auxquelles il a accès via le serveur Web, et cela en une seule commande.
Comment les détecter ?
Les injections se faisant via des requêtes HTTP, elles sont identifiables dans les journaux du serveur Web bien qu’elles soient le plus souvent obscurcies. Par exemple, nous retrouvons dans les journaux le code MsSQL cité plus haut sous la forme (les données « castées » ont été tronquées) :
2008-12-24 23:59:59 192.168.0.2 POST
/site/page_vulnerable.asp?section=acces;DECLARE%20@S%20NVARCHAR(4000);SET%20@S=CAST(0x4400450043004C00410052004500[…]7200%20AS%20NVARCHAR(4000));EXEC(@S);– 80 – 192.168.0.3 Mozilla/3.0+(compatible;+Indy+Library) 200 0 0 40126 2476
Nous voyons qu’un tableau de 4.000 caractères est créé (DECLARE @S NVARCHAR(4000)) sur lequel la requête est castée (SET @S=CAST(0x4400[…]7200 ). Ce tableau est ensuite exécuté (EXEC(@S)). La commande qui nous intéresse apparaît sous la forme d’une suite de nombres et n’est donc pas directement lisible, cependant la présence de « CAST » et « EXEC » est souvent synonyme de tentative d’injection.
Les actions sur les bases de données peuvent être journalisées. Un grand nombre de modifications en un temps très court peut laisser présager une injection SQL de ce type.
Ces attaques modifient les pages lues par les internautes. En surveiller quelques unes peut permettre de détecter une compromission. Cette surveillance peut être faite sur les pages retournées par le serveur Web ou directement sur les champs de « contenu » de la base.
Des tests d’intégrité peuvent être mis en place localement sur le serveur afin de déceler toute modification des configurations d’applications ou toute modification de certaines tables de données. Ces mêmes tests peuvent également être effectués à distance par le biais de requêtes automatisées (utilitaire wget par exemple).
Comment s’en protéger
S’il est bon de détecter les compromissions, il vaut bien mieux les prévenir. Nous avons vu dans les exemples précédents que les attaques reposaient majoritairement sur des faiblesses liées à la façon dont sont traités les paramètres entrants. Pour éviter cela, les valeurs autorisées en entrée doivent être strictement limitées au nécessaire et il faut contrôler la présence de caractères interdits.
Il faut s’assurer que des contrôles sémantiques et syntaxiques sont effectués sur chaque variable échangée. Ces contrôles doivent être faits sur le serveur et compléter éventuellement par des codes dynamiques interprétés sur les navigateurs des visiteurs. Des outils existent pour contrôler partiellement ces points de développement. Ainsi un champ « âge » ne doit accepter que des entiers compris entre 1 et 130 dans un encodage défini.
Avant de transmettre la requête à la base, il faut vérifier qu’elle ne contient pas de caractères spéciaux qui permettraient l’exécution des commandes supplémentaires, comme par exemple « ; », guillements ou autres apostrophes
Pour pouvoir modifier la base, l’utilisateur « serveur Web » doit avoir les droits adéquats. Ils doivent donc être le plus restrictifs possibles. Dans le cas d’un annuaire consultable en ligne, mais mis à jour via une procédure interne, il n’y a aucune raison que l’utilisateur «serveur » puisse modifier la base. Les droits accordés aux utilisateurs de la base doivent être cohérents.
Enfin, la mise en place d’une passerelle applicative – serveur mandataire inverse (reverse proxy) – peut compléter cette architecture de protection. Elle contrôlerait les requêtes HTTP à la recherche de chaînes de caractères pouvant caractériser une tentative d’injection. Par exemple la présence de CAST et EXEC dans la même requête.
Par Fabien Pouget et Benoit Moreau (CERTA)
Note
[1] Les exemples sont basés sur les SGBDR MySQL ou MsSQL et le langage PHP mais les principes restent valables et sont facilement transposables aux autres logiciels.
Pour aller plus loin
– Le bloc-notes de Microsoft sur les incidents constatés en mars et juin 2008 et notamment :
http://blogs.technet.com/neilcar/archive/2008/03/14/anatomy-of-sql-injection-incident.aspx
– Le bulletins d’actualité du CERTA traitant le sujet :
http://www.certa.ssi.gouv.fr/site/CERTA-2008-ACT-003.pdf
http://www.certa.ssi.gouv.fr/site/CERTA-2008-ACT-012.pdf
http://www.certa.ssi.gouv.fr/site/CERTA-2008-ACT-016.pdf
http://www.certa.ssi.gouv.fr/site/CERTA-2008-ACT-019.pdf
http://www.certa.ssi.gouv.fr/site/CERTA-2008-ACT-027.pdf
http://www.certa.ssi.gouv.fr/site/CERTA-2008-ACT-030.pdf
– Le bloc-notes de Internet Storm Center ISC SANS du 16 avril 2008 :
http://isc.sans.org/diary.html?storyid=4294
– Les bases de connaissances Microsoft publiées le 24 juin 2008 :
http://support.microsoft.com/?kbid=954476
http://www.microsoft.com/technet/security/advisory/954462.mspx
– Article de Microsoft, << prévenir les injections SQL en ASP >> :
Réagissez à cet article
Vous avez déjà un compte ? Connectez-vous et retrouvez plus tard tous vos commentaires dans votre espace personnel.
Inscrivez-vous !
Vous n'avez pas encore de compte ?
CRÉER UN COMPTE