Comment la Sécurité DataSunrise protège contre les Injections SQL
Dans cet article, nous vous démontrons comment DataSunrise prévient les injections SQL, qui sont l’un des instruments de piratage les plus populaires pour compromettre les applications web. Pour vous montrer ce qui se passe exactement lorsque DataSunrise intercepte une requête malveillante, nous réalisons un test de pénétration avec un logiciel dédié.
Sqlmap
Bien qu’il existe de nombreuses applications diverses dédiées à la réalisation d’évaluations automatisées de vulnérabilité, nous utilisons l’utilitaire Sqlmap dans notre expérience actuelle. Ce programme gratuit et open-source est écrit en langage Python et est facile à utiliser grâce à son interface en ligne de commande.
Selon la description officielle, Sqlmap peut utiliser les techniques d’injection SQL suivantes pour les tests de pénétration :
Blind basé sur les booléens
Sqlmap ajoute au paramètre vulnérable de la requête HTTP une instruction SQL syntaxiquement valide contenant une sous-requête SELECT ou toute autre instruction SQL utilisée pour récupérer les résultats de la base de données. Sqlmap compare ensuite chaque réponse HTTP à la requête originale et récupère la sortie de l’instruction injectée caractère par caractère.
Blind basé sur le temps
Sqlmap ajoute au paramètre vulnérable une instruction syntaxiquement valide contenant une requête qui provoque un délai dans le SGBD back-end pendant un certain nombre de secondes. Ensuite, l’utilitaire effectue une comparaison entre le temps de réponse original et le temps passé sur la réponse de la requête injectée, puis déduit la sortie de l’instruction injectée caractère par caractère.
Basé sur les erreurs
Sqlmap ajoute au paramètre vulnérable de la requête HTTP une chaîne d’instructions syntaxiquement invalide provoquant un message d’erreur spécifique à la base de données. Sqlmap analyse ensuite la réponse HTTP en essayant de trouver des messages d’erreur contenant le code SQL injecté et la sortie de la sous-requête. Cette méthode d’injection SQL ne fonctionne que si le SGBD est configuré pour afficher les messages d’erreur du SGBD back-end.
Basé sur les requêtes UNION
Sqlmap ajoute au paramètre vulnérable de la requête HTTP une instruction SQL syntaxiquement valide commençant par UNION ALL SELECT. Cette méthode est utile lorsque la page de l’application web utilise une boucle FOR ou équivalent pour passer la sortie de l’instruction SELECT, de sorte que chaque ligne de la sortie de la requête est affichée dans le contenu de la page. Sqlmap est capable d’exploiter des vulnérabilités “d’injection SQL de requête UNION partielle” également. Ces vulnérabilités se produisent lorsque la boucle FOR n’est pas utilisée et que seule la première entrée de la sortie de la requête est affichée.
Basé sur les requêtes empilées (piggybacking)
Si l’application web cible prend en charge les requêtes empilées, Sqlmap ajoute au paramètre vulnérable de la requête HTTP un caractère point-virgule ( ; ) suivi de l’instruction SQL à injecter. Cette technique est utilisée pour effectuer l’injection d’instructions SQL autres que SELECT (comme les instructions de définition de données ou de manipulation de données). Potentiellement, cette méthode peut être utilisée pour obtenir un accès en lecture/écriture au système de fichiers et l’exécution de commandes système, selon le SGBD back-end et les privilèges de l’utilisateur de la session.
Comme vous pouvez le voir, Sqlmap est un outil puissant capable non seulement de révéler les vulnérabilités mais aussi de les exploiter avec diverses techniques d’injection SQL. Pour en savoir plus sur les méthodes de détection des injections SQL.
Préparatifs pour les tests
Pour effectuer notre démonstration, nous avons besoin d’une application “dummy test” à injecter par SQL, nous utilisons donc un simple serveur web écrit en Python. Ce serveur est conçu pour afficher des informations provenant de la base de données définie par les paramètres dans la chaîne URL. Nous avons sauvegardé le code du serveur web dans le fichier webserv_inj.py :
import re import urllib.request from http.server import BaseHTTPRequestHandler, HTTPServer from urllib.parse import urlparse import pyodbc global dbconnection global dbcursor class InjectedServer(BaseHTTPRequestHandler): def do_GET(self): self.send_response(200) self.send_header("Content-type", "text/html charset=windows-1251") self.end_headers() o = urlparse(self.path) params = urllib.request.unquote(o.query) m = re.search("id=(?P[^;]+);name=(?P[^;]+)", params) id = m.group("id") name = m.group("name") dbconnection = pyodbc.connect( "Driver=PostgreSQL ODBC Driver(ANSI);Server=localhost;Port=54321;Database=test_db;Uid=postgres;Pwd=admin;UseServerSidePrepare=1") dbcursor = dbconnection.cursor() queryStr = "select * from injected_table where id = " + id + " and name = '" + name + "' order by id" dbcursor.execute(queryStr) result = dbcursor.fetchall() for row in result: self.wfile.write(bytes(str(row[0]), "utf-8")) self.wfile.write(bytes(str(row[1]), "utf-8")) self.wfile.write(bytes(str(row[2]), "utf-8")) myServer = HTTPServer(("127.0.0.1", 6589), InjectedServer) try: myServer.serve_forever() except KeyboardInterrupt: pass myServer.server_close()
Nous allons essayer de pirater notre serveur web auto-construit et d’obtenir des données d’une base de données PostgreSQL. Nous avons utilisé le code suivant pour créer une nouvelle table de base de données (“injected_table“) et la remplir avec deux entrées :
CREATE TABLE injected_table ( id integer, name character varying(200), surname character varying(200) ) INSERT INTO injected_table VALUES (1, Bob, Martin); INSERT INTO injected_table VALUES (2, Denis, Morgan);
Voici à quoi ressemble la nouvelle table dans PGAdmin
Ensuite, nous lançons notre serveur en exécutant la commande suivante via l’invite de commande de Windows :
python webserv_inj.py
Pour être sûr que tout fonctionne comme prévu, nous envoyons la requête suivante au serveur web via un navigateur web :
http://127.0.0.1:6589/?id=2;name=Denis
En conséquence, le serveur web affiche l’entrée “injected_table” avec ID=2 et Name=Denis
Tester le serveur web avec Sqlmap
Il est maintenant temps de vérifier si notre serveur web peut être injecté par SQL.
Nous commençons d’abord la procédure de test de Sqlmap via l’invite de commande :
python.exe sqlmap.py -u http://127.0.0.1:6589/?id=2;name=Denis
Une fois le processus de test terminé, jetons un coup d’œil au fichier journal de Sqlmap (il a été créé automatiquement et sauvegardé dans le dossier “output”).
Sqlmap a identifié les points d'injection suivants avec un total de 50 requêtes HTTP(s) : --- Paramètre : id (GET) Type: blind basé sur les booléens Titre : AND blind basé sur les booléens - clause WHERE ou HAVING Charge utile : id=2;name=Denis' AND 8150=8150 AND 'lsHq'='lsHq Type: blind basé sur le temps AND/OR Titre : PostgreSQL > 8.1 basé sur le temps AND Charge utile : id=2;name=Denis' AND 9061=(SELECT 9061 FROM PG_SLEEP(5)) AND 'TLxE'='TLxE Type : requête UNION Titre : Requête UNION générique (NULL) - 3 colonnes Charge utile : id=2;name=Denis' UNION ALL SELECT NULL,NULL,(CHR(113)|| CHR(112)||CHR(120)||CHR(120)||CHR(113))||(CHR(88)||CHR(109)||CHR(66)||CHR(103)||CHR(114)|| CHR(69)||CHR(83)||CHR(119)||CHR(113)||CHR(98)||CHR(110)||CHR(73)||CHR(90)||CHR(83)|| CHR(90)||CHR(121)||CHR(113)||CHR(102)||CHR(85)||CHR(117)||CHR(107)||CHR(72)||CHR(78)|| CHR(101)||CHR(79)||CHR(90)||CHR(112)||CHR(120)||CHR(74)||CHR(106)||CHR(114)||CHR(105)|| CHR(85)||CHR(84)||CHR(71)||CHR(104)||CHR(71)||CHR(89)||CHR(75)||CHR(111))||(CHR(113)|| CHR(22)||CHR(107)||CHR(122)||CHR(113))-- - --- SGBD back-end : PostgreSQL
Comme le journal le montre, Sqlmap a identifié avec succès la version du SGBD (PostgreSQL) et a déterminé que le paramètre “ID” est vulnérable à l’injection SQL. De plus, Sqlmap nous a proposé trois variantes d’instructions SQL qui peuvent être utilisées pour effectuer l’injection SQL (chaînes “Payload“).
Paramètres de règle de sécurité de DataSunrise (section des injections SQL)
Et maintenant, nous allons vérifier l’efficacité de DataSunrise pour protéger le serveur web vulnérable (et la base de données PostgreSQL) contre les injections SQL.
Nous avons créé une règle de sécurité “injection SQL” (voir le guide utilisateur de DataSunrise pour les détails) et supprimé les fichiers créés par Sqlmap lors du premier test.
Nous lançons à nouveau la procédure de test Sqlmap (comme décrit ci-dessus) et à la fin du test, nous vérifions le journal de l’utilitaire (notez que Sqlmap n’a pas pu créer un fichier journal, nous utilisons donc son journal de ligne de commande).
Selon le journal, Sqlmap a déterminé que tous les paramètres testés ne sont pas vulnérables à l’injection SQL, y compris le paramètre “ID” qui était précédemment marqué comme injectable.
Conclusion
Notre expérience prouve que le pare-feu DataSunrise est très efficace pour prévenir les injections SQL. Néanmoins, pour la meilleure protection possible contre les menaces les plus complexes, il est nécessaire de prendre des mesures de protection étendues telles que les suivantes :
- Suivi des meilleures pratiques de l’industrie pour développer des applications web résistantes aux injections SQL
- Réalisations de tests de hacker simulés sur vos bases de données et applications web pour révéler les vulnérabilités potentielles (ce que l’on appelle “tests de pénétration”)
- Audit continuel des bases de données pour détecter les violations et fuites de données
- Suivi des recommandations des développeurs et des lignes directrices pour une utilisation sûre des bases de données et des logiciels associés.
DataSunrise prend en charge toutes les principales bases de données et entrepôts de données tels qu’Oracle, Exadata, IBM DB2, IBM Netezza, MySQL, MariaDB, Greenplum, Amazon Aurora, Amazon Redshift, Microsoft SQL Server, Azure SQL, Teradata et bien plus encore. Vous êtes invités à télécharger une version d’essai gratuite si vous souhaitez l’installer sur vos locaux. Si vous êtes un utilisateur de cloud et que vous exécutez votre base de données sur Amazon AWS ou Microsoft Azure, vous pouvez l’obtenir sur AWS market place ou Azure market place.