Injection SQL, quelques exemples



Documents pareils
Mysql. Les requêtes préparées Prepared statements

Sécurité des sites Web Pas un cours un recueil du net. INF340 Jean-François Berdjugin

SQL MAP. Etude d un logiciel SQL Injection

OpenPaaS Le réseau social d'entreprise

Notes de cours : bases de données distribuées et repliquées

Bases de données et sites WEB

Principales failles de sécurité des applications Web Principes, parades et bonnes pratiques de développement

COMMANDES SQL... 2 COMMANDES DE DEFINITION DE DONNEES... 2

Olivier Mondet

Création et Gestion des tables

Bases de données et sites WEB Licence d informatique LI345

Langage SQL (1) 4 septembre IUT Orléans. Introduction Le langage SQL : données Le langage SQL : requêtes

Vulnérabilités et sécurisation des applications Web

Pratique et administration des systèmes

Bases de données relationnelles

PHP et mysql. Code: php_mysql. Olivier Clavel - Daniel K. Schneider - Patrick Jermann - Vivian Synteta Version: 0.9 (modifié le 13/3/01 par VS)

ECR_DESCRIPTION CHAR(80), ECR_MONTANT NUMBER(10,2) NOT NULL, ECR_SENS CHAR(1) NOT NULL) ;

Langage SQL : créer et interroger une base

Cours Bases de données 2ème année IUT

SGBDR. Systèmes de Gestion de Bases de Données (Relationnelles)

Licence de MIDO - 3ème année Spécialités Informatique et Mathématiques Appliquées

laposte.net) Ministère de l'éducation nationale Atelier sécurité Rabat RALL 2007

PHP 5. La base de données MySql. A. Belaïd 1

les techniques d'extraction, les formulaires et intégration dans un site WEB

Bases de Données relationnelles et leurs systèmes de Gestion

1. Qu'est-ce que SQL? La maintenance des bases de données Les manipulations des bases de données... 5

A QUOI SERVENT LES BASES DE DONNÉES?

Gestion des utilisateurs et de leurs droits

Langage propre à Oracle basé sur ADA. Offre une extension procédurale à SQL

CREATION WEB DYNAMIQUE

A.E.C. GESTION DES APPLICATIONS TECHNOLOGIE DE L'INFORMATION LEA.BW

Cours Bases de données 2ème année IUT

Le langage SQL pour Oracle - partie 1 : SQL comme LDD

Bases de Données et Internet

Module Administration BD Chapitre 1 : Surcouche procédurale dans les SGBDS

ISC Système d Information Architecture et Administration d un SGBD Compléments SQL

Remote Cookies Stealing SIWAR JENHANI (RT4) SOUHIR FARES (RT4)

ContactForm et ContactFormLight - Gestionnaires de formulaire pour Prestashop Edité par ARETMIC S.A.

INSTALLATION DE L APPLICATION DU CONTEXTE ITASTE

Gestion de base de données

Procédures Stockées WAVESOFT ws_sp_getidtable Exemple : ws_sp_getnextsouche Exemple :... 12

Introduction à JDBC. Accès aux bases de données en Java

1. Base de données SQLite

I. MySQL : Serveur et SGBD

Le Langage De Description De Données(LDD)

Mysql avec EasyPhp. 1 er mars 2006

Quelques patterns pour la persistance des objets avec DAO DAO. Principe de base. Utilité des DTOs. Le modèle de conception DTO (Data Transfer Object)

Les BASES de DONNEES dans WampServer

Java et les bases de données: JDBC: Java DataBase Connectivity SQLJ: Embedded SQL in Java. Michel Bonjour

Historisation des données

Partie II Cours 3 (suite) : Sécurité de bases de données

PHP 4 PARTIE : BASE DE DONNEES

WDpStats Procédure d installation

CHAPITRE 4 POLITIQUES DE CONTRÔLES DES ACCÈS SOUS ORACLE ADMINISTRATION ET TUNING DE BASES DE DONNÉES 10/05/2015 RESPONSABLE DR K.

Java et les bases de données

Le langage SQL (première partie) c Olivier Caron

Sécurité des applications web. Daniel Boteanu

Fonctionnement et mise en place d un reverse proxy sécurisé avec Apache. Dimitri ségard 8 mai 2011

The Mozilla Art Of War. David Teller. 20 septembre Laboratoire d Informatique Fondamentale d Orléans. La sécurité des extensions.

Cours SQL. Base du langage SQL et des bases de données

Protection des protocoles

Gestion de stock pour un magasin

Exemple accessible via une interface Web. Bases de données et systèmes de gestion de bases de données. Généralités. Définitions

Sommaire. Etablir une connexion avec une base de données distante sur PostGreSQL

Mise en oeuvre d'une base de données mono-utilisateur avec SQLite

Programmation Web. Madalina Croitoru IUT Montpellier

A QUOI SERVENT LES BASES DE DONNÉES?

Vulnérabilités et solutions de sécurisation des applications Web

Stockage du fichier dans une table mysql:

Partie 0 : Gestion des tablespace et des utilisateurs... 3

PHP et les Bases de données - Généralités

SYNC FRAMEWORK AVEC SQLITE POUR APPLICATIONS WINDOWS STORE (WINRT) ET WINDOWS PHONE 8

Jérôme FESSY. IUT de Paris 5. Base de Données. Cours Introductif. Base de Données

Modélisation PHP Orientée Objet pour les Projets Modèle MVC (Modèle Vue Contrôleur) Mini Framework

API FTP SMSENVOI V1.1

Les bases de données

Base de données relationnelle et requêtes SQL

Gestion des utilisateurs, des groupes et des rôles dans SQL Server 2008

Créer le schéma relationnel d une base de données ACCESS

SYSTÈMES D INFORMATIONS

Bases de données Oracle Virtual Private Database (VPD) pour la gestion des utilisateurs d applications

INTRODUCTION AU CMS MODX

Bases de SQL. Hacks 1-6 CHAPITRE UN

Java DataBaseConnectivity

Sage 100 CRM - Guide de la Fusion Avancée Version 8. Mise à jour : 2015 version 8

Introduction au langage C

Attaques applicatives

PHP. Bertrand Estellon. 26 avril Aix-Marseille Université. Bertrand Estellon (AMU) PHP 26 avril / 214

Bases de données avancées

SQL Historique

Sécurité des réseaux Les attaques

Optimisations des SGBDR. Étude de cas : MySQL

Aide à la Détection de Faiblesses d un site Web Mandataire inverse, Modsecurity

NFA 008. Introduction à NoSQL et MongoDB 25/05/2013

WEB APPLICATION FIREWALL AVEC APACHE ET MOD_SECURITY

Retour d expérience sur Prelude

Transcription:

Injection SQL, quelques exemples Stéphane Bortzmeyer <stephane+blog@bortzmeyer.org> Première rédaction de cet article le 19 mai 2009 L injection SQL est une technique d attaque utilisée contre les bases de données SQL dès lors qu elles sont accessibles de l extérieur, via une interface qui ne permet normalement pas de taper des commandes SQL quelconques. Cette technique est ancienne, banale, et, comme vient de le rappeler l attaque contre plusieurs registres de noms de domaine <http://www.bortzmeyer.org/attaques-registres-noms. html>, elle est largement utilisée. Je ne vais pas faire un tutoriel complet sur l injection SQL, il en existe plusieurs en ligne comme la page de Wikipédia ou une bonne discussion sur StackOverflow <http://stackoverflow.com/ questions/332365/xkcd-sql-injection-please-explain>. Je veux juste montrer quelques exemples. Pour tous les cas qui suivent, on lance le programme en ligne de commande, ce qui offre évidemment bien plus de possibilités à l attaquant. Mais les attaques par injection SQL sont parfaitement possibles dans d autres circonstances, et sont en général pratiquée via une page Web. D abord, le principe : lorsqu un programme fait une requête SQL qui contient des paramètres spécifiés par l utilisateur, l injection SQL consiste à mettre dans ces paramètres du code SQL, avec des caractères qui déclencheront l injection. L exemple archétypal est fourni par le célèbre dessin de xkcd <http: //xkcd.com/327/>. Commençons avec un programme Python qui reçoit un paramètre sur la ligne de commandes et l inclut dans une requête SQL SELECT. Ce programme se connecte à une base de données PostgreSQL. La table est créée ainsi : CREATE TABLE students (id SERIAL UNIQUE NOT NULL, name TEXT UNIQUE NOT NULL, birthdate DATE DEFAULT now()); INSERT INTO students (name) VALUES ( durand ); INSERT INTO students (name) VALUES ( toto ); INSERT INTO students (name) VALUES ( martin ); 1

2 Le programme Python est : import psycopg import sys name = sys.argv[1] # Il y a une subtilité avec l "autocommit", je vous laisse la découvrir cursor.execute("select * FROM Students WHERE name= %s " % name) Exécuté, ce programme donnera : % python test1.py toto (2, toto, <mx.datetime.datetime object for 2009-05-18 00:00:00.00 at b7e51aa0>) Si on fait enregistrer les requêtes par PostgreSQL (log_statement = all ), on voit bien ce qui a été envoyé au SGBD : 2009-05-18 21:47:58 CEST LOG: statement: SELECT * FROM students WHERE name= toto ; Maintenant, si un méchant fait une injection SQL, il tapera, par exemple : % python test1.py "toto ; DROP TABLE Students; SELECT " (,) et la table Students sera détruite. Le SGBD avait reçu : 2009-05-18 21:39:37 CEST LOG: statement: SELECT * FROM students WHERE name= toto ; DROP TABLE students; SEL et a donc, après le premier SELECT, exécuté l instruction DROP... Évidemment, dans ce cas, l attaquant a accès au SGBD et peut faire n importe quelle requête directement. Mais imaginons que le code Python ci-dessus aie été executé via una page Web, par exemple parce qu il fait partie d une application WSGI <http://www.bortzmeyer.org/wsgi.html>. Alors, le code sera exécuté avec les privilèges du compte qui fait tourner le WSGI (par exemple apache) et l attaquant n aura pas de compte du tout. Dans ce cas, l injection SQL lui permettra de faire ce qu il ne pouvait pas faire autrement. Elle représente donc une sérieuse faille de sécurité. Comment empêcher l injection SQL? Une première réaction est de filtrer la requête pour en retirer les caractères dangereux :

3 import re if re.search("[ ;]", name): raise InjectionSQL mais cette méthode est peu sûre : il est difficile de s assurer qu on a prévu tous les caractères dangereux (surtout si name est en Unicode). La norme SQL étant ce qu elle est, chaque SGBD a souvent les siens (par exemple, la barre oblique inverse est un caractère spécial pour certains SGBD). Il est plus sûr de procéder en sens inverse. Plutôt que d interdire les méchants, n autoriser que les bons : if not re.search("ˆ[a-z0-9]+$", name): raise InjectionSQL Ici, l expression rationnelle ˆ[a-z0-9]+$ teste que la variable est composée entièrement de lettres ASCII minuscules et de chiffres. De tels tests sont très sûrs mais souvent trop restrictifs. Ici, si on veut enregistrer une personne nommé O Reilly ou D Alembert, on est coincés. Une telle approche tout ce que je ne connais pas est interdit mène souvent à des restrictions injustifiées <http://www.bortzmeyer.org/arreter-d-interdire-des-ad html>. Pour combattre l injection SQL, il est donc préférable d utiliser une autre méthode. Il y en a deux bonnes, faire fabriquer la requête par la bibliothèque d accès, ou bien par le SGBD (requêtes préparées), et pas directement par le programmeur. On va illustrer la première en Python et la seconde en C. Voici un exemple où la requête est fabriquée par la bibliothèque d accès au SGBD, ici psycopg : name = sys.argv[1] cursor.execute("select * FROM students WHERE name=%(username)s;", { username : name}) Un tel code est protégé contre les injections SQL. La bibliothèque psycopg <http://initd.org/ pub/software/psycopg/>, en voyant %(username)s va le remplacer par la valeur de l entrée username du dictionnaire passé en second paramètre, effectuant toutes les transformations nécessaires pour que les caractères dangereux <http://www.bortzmeyer.org/caracteres-dangereux.html> soient neutralisés (et ces logiciels connaissent mieux les règles que vous, faites leur confiance). Ici, PostgreSQL a vu (regardez bien les apostrophes) : 2009-05-18 21:51:01 CEST LOG: statement: SELECT * FROM students WHERE name= toto ; DROP TABLE students; SELECT Et la table n est plus détruite, PostgreSQL a simplement cherché un utilisateur de nom "toto ; DROP TABLE students; SELECT " et ne l a évidemment pas trouvé. Dans tous les cas, il faut noter que le seul fait d utiliser un langage de programmation de haut niveau ne protège pas, contrairement à ce qui se passe avec d autres attaques comme les débordements de tampons. Les attaques par injection SQL concernent tout le monde. Dans certains cas, le typage peut aider à empêcher l injection SQL. Si on cherche la table selon un paramètre numérique :

4 id = int(sys.argv[1]) connection.set_isolation_level(0) cursor.execute("select * FROM students WHERE id=%i;" % id) Alors, il n y a pas de risque. la conversion de l argument sys.argv[1] en entier suffit à garantir qu il n y aura pas de caractères dangereux. Mais les chaînes de caractères sont, elles, toujours vulnérables. Un petit retour sur l exemple Python sûr. Si on veut éviter de construire un dictionnaire pour le passer en second paramètre, on peut utiliser le dictionnaire prédéfini renvoyé par globals() et on utilise alors directement ses variables Python, ici name : cursor.execute("select * FROM students WHERE name=%(name)s;", globals()) On peut aussi faire varier la syntaxe, cette forme, qui n utilise plus les noms des paramètres, uniquement leur position, est également sûre, on n utilise pas l opérateur d interpolation de Python (le %) : cursor.execute("select * FROM students WHERE name=%s;", (name,)) La lecture de la spécification de l API Python pour les bases de données, PEP 249 <http://www. python.org/dev/peps/pep-0249/> est recommandée si on veut tous les détails de l association des paramètres avec leur valeur. Le style %(name)s est nommé pyformat, celui avec les positions numériques est numeric (mais n est pas géré par psycopg, chaque bibliothèque peut choisir son style de paramètres, afficher MABIBLIOTHEQUE.parmastyle permet de savoir quelle est le style de MA- BIBLIOTHEQUE). Par exemple, avec le module d accès à SQLite, PySQLite <http://docs.python. org/library/sqlite3.html>, on écrit souvent cursor.execute("insert INTO table VALUES ( hello world,?,?)", (user, message)), les points d interrogation étant remplacés par les paramètres, avec échappement des caractères dangereux. Et en C? Les injections SQL existent aussi. Si on exécute l insertion ainsi (le code C complet est en (en ligne sur http://www.bortzmeyer.org/files/insert-sql-with-injection.c), on utilise l interface libpq <http://www.postgresql.org/docs/current/interactive/libpq.html> de PostgreSQL) : snprintf(sql_command, MAX_SQL_SIZE, "SELECT * FROM students WHERE name= %s ;", name); result = PQexec(conn, sql_command); on est tout aussi vulnérable qu en Python et pour les mêmes raisons. Une solution est de neutraliser ( to escape ) les caractères dangereux avec PQescapeStringConn. Une méthode souvent plus élégante est d utiliser des requêtes préparées (le code complet est en (en ligne sur http://www.bortzmeyer. org/files/insert-sql-without-injection.c)) :

5 params[0] = argv[1]; result = PQprepare(conn, "MyInsertion", "SELECT * FROM students WHERE name=$1;", NPARAMS, NULL); result = PQexecPrepared(conn, "MyInsertion", NPARAMS, (const char **) params, NULL, NULL, 0); Comme les requêtes préparées sont gérées par le SGBD, celui-ci peut afficher dans son journal la requête et la valeur des paramètres. Ici, pour une requête normale : 2009-05-19 09:56:32 CEST LOG: execute MyInsertion: SELECT * FROM students WHERE name=$1; 2009-05-19 09:56:32 CEST DETAIL: parameters: $1 = toto et ici pour une tentative d injection SQL : 2009-05-19 09:43:17 CEST LOG: execute MyInsertion: SELECT * FROM students WHERE name=$1; 2009-05-19 09:43:17 CEST DETAIL: parameters: $1 = toto ; DROP TABLE Students; SELECT Bien sûr, rien n est gratuit, les requêtes préparées ont des avantages (sécurité contre l injection SQL, possibilité pour le SGBD de passer du temps à les optimiser car il peut espérer qu elles seront réutilisées) mais aussi des inconvénients puisque, par exemple, le SGBD doit désormais optimiser la requête sans disposer des données et donc le risque d avoir un plan d exécution sous-optimal <http://archives. postgresql.org/pgsql-jdbc/2009-05/msg00034.php>. (Merci à Marc Cousin pour ce point.) Comme avec tous les problèmes de sécurité, il est recommandé d adopter une défense en profondeur. Même si les assaillants ont pris pied sur l enceinte du château, il faut que le donjon continue à résister. Dans le cas d un SGBD, cela veut dire que le compte sous lequel se connecte l application au SGBD doit avoir des privilèges minimaux. Par exemple, si l application ne fait que lire la base, il faut uniquement lui donner le privilège SELECT et certainement pas INSERT ou DELETE. Un exemple est le moteur de recherche de ce blog </search>. Comme l application (écrite en Python et reposant sur PostgreSQL) n a jamais à modifier les données, l utilisateur qui exécute la page Web, apache, n a que le droit de lecture. Ainsi, même en cas d injection SQL sur cette page, les dégâts seront limités. Voici l affichage des privilèges <http://www.postgresql.org/docs/current/interactive/ sql-grant.html> : blog=> \dp blog.articles Access privileges for database "blog" Schema Name Type Access privileges --------+----------+-------+---------------------------------------------- blog articles table {stephane=arwdxt/stephane,apache=r/stephane} (1 row) qui se lit stephane a tous les droits, apache a uniquement le droit de lecture (r pour read ). Il existe des outils de tests de vulnérabilités : BSQL Hacker <http://www.darknet.org.uk/2008/09/bsql-hacker-automated-sql-injection-fram >, SQL Injection <https://addons.mozilla.org/en-us/firefox/addon/6727> (une extension à Firefox), que je trouve bien faite et pratique, HackBar <https://addons.mozilla.org/en-us/firefox/addon/3899>, une autre extension Firefox que je n arrive pas à faire fonctionner, SQLmap <http://sqlmap.sourceforge.net/>, un excellent testeur, très riche, en ligne de commandes. Par exemple, sqlmap -u http://www.bortzmeyer.org/search\?pattern=toto va automatiquement tester plein de méthodes d injection SQL sur mon moteur de recherche. Pour en savoir plus : Sur l excellent site StackOverflow <http://www.bortzmeyer.org/stack-overflow.html>, on trouve de nombreuses discussions sur l injection SQL <http://stackoverflow.com/questions/ tagged/sql-injection>, Plein d exemples amusants et d aide en <http://ha.ckers.org/sqlinjection/>.