Mysql est la base de données Open Source la plus répandue. Cet article vous présente les techniques de base pour sécuriser votre serveur Mysql.

Sécurisation d'un serveur Mysql

Comptes et mots de passe

Au lieu du classique login/password, Mysql gère un triplet login/password/source pour authentifier les utilisateurs. Ainsi, un utilisateur peut posséder un mot de passe différent selon son adresse de connection. Lors de son installation, Mysql crée deux comptes administrateurs de login root qui peuvent se connecter depuis localhost ou depuis le nom renvoyé par hostname. Ces comptes sont sans mot de passe. On a donc :
HostUserPassword
localhostroot 
christophe.global-secure.frroot 

La première étape est de se connecter à la base mysql en tant qu'administrateur :
[kmaster@p500 kmaster]$ mysql -u root mysql
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1 to server version: 3.23.49

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql>
Changeons le mot de passe sur le compte root ou plus exactement définissons le :
mysql> SET PASSWORD FOR root@localhost=PASSWORD('new_password');
Query OK, 0 rows affected (0.00 sec)

mysql> mysql> exit
Bye
Le second compte administrateur est lui aussi sans mot de passe et local: il permet une connexion réseau depuis le serveur vers lui-même. Comme il est inutile, supprimons le après s'être reconnecté :
[kmaster@p500 kmaster]$ mysql -u root mysql -p
Enter password:
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2 to server version: 3.23.49

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> DELETE FROM user WHERE Host='christophe.global-secure.fr' AND User='root';
Query OK, 1 row affected (0.00 sec)
Il faut noter que si on veut que l'administrateur puisse se connecter à distance, il faut que le Host du compte indique le nom ou l'adresse IP de son poste client ou bien le caractère % pour qu'il puisse se connecter depuis n'importe où. Des connexions anonymes sont possibles, et des comptes sans mots de passe existent encore. Il nous faut donc les supprimer de sorte que seuls les utilisateurs dûment authentifiés puissent se connecter :
mysql> DELETE FROM user WHERE Password='';
Query OK, 2 rows affected (0.00 sec)
Mysql a créé une base de test, elle nous est inutile :
mysql> DROP DATABASE test;
Query OK, 0 rows affected (0.00 sec)
Par défaut, la base test et toutes les bases commençant par "test_" si elles existent sont accessibles à toute personne connectée :
mysql> DELETE FROM db WHERE db='test' OR db='test\_%';
Query OK, 2 rows affected (0.00 sec)
Quand Mysql démarre, le contenu des tables de privilèges est chargé en mémoire. Seules les modifications effectuées avec GRANT, REVOKE ou SET PASSWORD sont prises en compte immédiatement. Les autres changement comme par exemple un INSERT ou un UPDATE nécessite de recharger les tables de privilèges. Activons donc les modifications :
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

Les privilèges

Un utilisateur peut avoir des privilèges s'appliquant à la totalité du système de base de données ou bien des privilèges sur certaines bases ou tables de la base. Seuls les comptes administrateurs doivent avoir des droits sur la totalité de la base. De manière générale, ces comptes doivent être réservés aux tâches d'administration :: création/suppression d'utilisateurs, de bases.

Pour créer un compte utilisateur pipo, pouvant se connecter de n'importe où, avec le droit d'effectuer diverses commandes sur la base pipodb (Utiliser CREATE DATABASE pipo pour créer la base), il suffit d'utiliser la commande GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,ALTER,DROP ON pipodb.* TO pipo@"%" IDENTIFIED BY "pwd";

Dans la mesure du possible, je conseille d'utiliser trois comptes par projet : un avec le droit SELECT pour les opérations de lecture, un autre avec les droits supplémentaires INSERT, UPDATE, DELETE pour réaliser les opérations d'écriture, et un dernier ayant aussi les privilèges CREATE, ALTER, DROP pour intervenir sur la structure des tables.

Les sécurités

Liste des bases de données

A l'aide de la commande SHOW DATABASES, un utilisateur obtient la liste de toutes les bases de données du serveur.

mysql -u pipo -p
Enter password:

mysql> show databases;
+----------+
| Database |
+----------+
| mysql    |
| pipodb   |
+----------+

Si on est parano, il est possible de désactiver cette commande, mais il est plus raisonnable de n'autoriser à lister que les bases sur lequel l'utilisateur a des droits. Dans le fichier /etc/my.cnf, section mysqld, ajouter safe-show-database.

mysql -u pipo -p
Enter password:

mysql> show databases;
+----------+
| Database |
+----------+
| pipodb   |
+----------+

Limiter les connexions

Le nombre de connexions est limité par le paramètre max_connections. Par exemple, pour limiter à 100 connexions simultanées, ajouter dans /etc/my.cnf la ligne set-variable = max_connections=100. Pour éviter qu'un utilisateur accapare toutes les connexions, limitons le nombre de connexions par utilisateur: set-variable = max_user_connections =50. Remarque, les paramètres (taille du cache pour les tris par exemple) de mysqld pour augmenter ses performances se spécifient de la même manière

Restriction réseau

Pour limiter les connexions à une interface, utiliser le paramètre bind-address :

netstat -tlnp
Connexions Internet actives (seulement serveurs)
Proto Recv-Q Send-Q Adresse locale          Adresse distante        Etat        PID/Program name
tcp        0      0 192.168.1.33:3306      0.0.0.0:*               LISTEN      2459/mysqld

Mais si aucune connexion depuis le réseau n'est requise, autant supprimer la couche de réseau avec --skip-networking.

Du coté des programmes, il y a généralement peu de chose à modifier pour ne pas utiliser le réseau. En C, le paramètre host de mysql_real_connect doit être remplacé par NULL ou localhost. En PHP, le paramètre host de mysql_connect doit être à vide. En Perl, au lieu de spécifier la source de données (DSN) sous la forme dbi:DriverName:database_name@hostname:port, on omet le nom d'hôte et le port.

Pour ceux qui ont besoin de communiquer via le réseau, les communications peuvent être protégées par du SSL. Se reporter à la documentation très complète de Mysql.

Chrooter Mysql

Mysql peut fonctionner dans un environnement chrooté, c'est-à-dire déporté dans une partie de l'arborescence. Comme Mysql fonctionne en tant qu'utilisateur, même en cas de faille de sécurité importante, le pirate ne peut pas accéder à la totalité du disque. Il reste cantonné à la nouvelle racine ainsi définie.

Cette configuration demande un peu de travail. Voici les différentes étapes pour chrooter Mysql dans le répertoire /services/chrooted-mysql/.

On commence par créer l'arborescence :

mkdir -p /services/chrooted-mysql/var/lib/
cd /services/chrooted-mysql
mkdir -p var/run etc tmp
chmod 1777 tmp

puis on y déplace les bases de données :

grep "mysql:" /etc/passwd > etc/passwd
mv /var/lib/mysql var/lib/
ln -s /services/chrooted-mysql/var/lib/mysql/ /var/lib/mysql
mv /var/run/mysqld var/run
ln -s /services/chrooted-mysql/var/run/mysqld/ /var/run/mysqld

Enfin, on ajoute les librairies dont a besoin Mysql pour fonctionner :

ldd /usr/libexec/mysqld
        libdl.so.2 => /lib/libdl.so.2 (0x4002c000)
        libpthread.so.0 => /lib/i686/libpthread.so.0 (0x40030000)
        libz.so.1 => /usr/lib/libz.so.1 (0x40044000)
        libcrypt.so.1 => /lib/libcrypt.so.1 (0x40052000)
        libnsl.so.1 => /lib/libnsl.so.1 (0x4007f000)
        libm.so.6 => /lib/i686/libm.so.6 (0x40094000)
        libc.so.6 => /lib/i686/libc.so.6 (0x42000000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
mkdir -p lib/i686 usr/lib
cp /lib/libdl.so.2 /lib/libcrypt.so.1 /lib/libnsl.so.1 /lib/ld-linux.so.2 lib
cp /lib/i686/libpthread.so.0 /lib/i686/libm.so.6 lib/i686/

Il faut aussi rajouter les librairies de résolution de nom :

cp /lib/libnss_compat.so.2 /lib/libnss_files.so.2 lib/

Et voila, il ne reste plus qu'à spécifier la nouvelle racine dans le fichier /etc/my.cnf: chroot=/services/chrooted-mysql.

Perte du mot de passe de l'administrateur

En cas de perte du mot de passe administrateur, relancer mysqld avec l'option --skip-grant-tables. Aucun mot de passe n'est alors nécessaire, et aucune vérification des droits n'est active. Il ne vous reste plus qu'à changer le mot de passe ou restaurer les paramètres défectueux.

Conclusion

J'espère vous avoir donner un bon aperçu des mécanismes de sécurité de Mysql. Sachez que ce serveur de base de données comporte plus d'une centaine de paramètres qui permettent de l'adapter aux besoins d'une grande variété d'applications. Un bon paramétrage permet d'augmenter de manière étonnante ses performances.


Christophe GRENIER - Consultant Sécurité chez Global Secure cgr@global-secure.fr