Meilleures pratiques pour renforcer les configurations de sécurité du serveur MySQL

Renforcez MySQL avec des utilisateurs à privilèges minimaux, des restrictions d'hôte, TLS, des paramètres my.cnf plus sûrs, des correctifs et un audit de base.

Meilleures pratiques pour renforcer les configurations de sécurité du serveur MySQL

Le renforcement de MySQL commence par une question simple : que gagnerait un attaquant si un mot de passe d'application fuyait ? Si la réponse est « toutes les bases de données depuis n'importe où », votre serveur a besoin d'utilisateurs plus stricts, de règles réseau et de configuration.

Utilisez ces pratiques pour réduire le rayon d'explosion d'une compromission sans rendre l'administration quotidienne pénible.

1. Gestion des utilisateurs et des accès : le principe du moindre privilège

Une gestion efficace des utilisateurs est fondamentale pour la sécurité de MySQL. Accorder aux utilisateurs uniquement les permissions dont ils ont absolument besoin est primordial.

Créer des utilisateurs spécifiques pour des applications spécifiques

Évitez d'utiliser l'utilisateur root pour les connexions d'application. Créez plutôt des utilisateurs dédiés avec des permissions granulaires.

CREATE USER 'my_app_user'@'localhost' IDENTIFIED BY 'StrongPassword123!';
GRANT SELECT, INSERT, UPDATE, DELETE ON `your_database`.* TO 'my_app_user'@'localhost';

Appliquer des mots de passe forts

Des mots de passe forts et uniques sont votre première ligne de défense. Utilisez le plugin de validation de mot de passe intégré de MySQL s'il est disponible.

  • Complexité : Mélangez majuscules, minuscules, chiffres et symboles.
  • Longueur : Visez au moins 12 à 16 caractères.
  • Unicité : Ne réutilisez jamais les mots de passe.
  • Rotation : Mettez en place une politique de changement régulier des mots de passe.

Vous pouvez activer le composant validate_password (MySQL 8.0+) ou le plugin (MySQL 5.7+) :

INSTALL COMPONENT 'file://component_validate_password';
-- OU pour les versions plus anciennes
INSTALL PLUGIN validate_password SONAME 'validate_password.so';

-- Configurer la politique de force (par exemple, MEDIUM pour 8+ caractères, mélange casse, chiffres, spéciaux)
SET GLOBAL validate_password.policy = MEDIUM;
SET GLOBAL validate_password.length = 12;

Supprimer les utilisateurs par défaut et inutilisés

MySQL peut inclure des comptes administratifs et internes. Gardez les comptes système requis comme mysql.session et mysql.sys intacts, mais supprimez les comptes anonymes et tout compte humain ou d'application que vous n'utilisez plus.

-- Pour identifier les utilisateurs anonymes :
SELECT user, host FROM mysql.user WHERE user = '';
-- Pour supprimer un utilisateur anonyme (s'il est trouvé) :
DROP USER ''@'localhost';

-- Pour supprimer les bases de données de test (si elles existent) :
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%';
FLUSH PRIVILEGES;

Restreindre l'accès à l'hôte

Limitez les comptes utilisateur à se connecter uniquement à partir d'adresses IP ou de noms d'hôte spécifiques. Évitez d'utiliser % comme caractère générique pour l'hôte, sauf en cas d'absolue nécessité et associé à d'autres contrôles de sécurité stricts.

-- L'utilisateur ne peut se connecter qu'à partir de localhost
CREATE USER 'admin'@'localhost' IDENTIFIED BY 'AnotherStrongPass!';

-- L'utilisateur ne peut se connecter qu'à partir d'une adresse IP spécifique
CREATE USER 'backup_user'@'192.168.1.100' IDENTIFIED BY 'BackupPass!';

Soyez prudent avec GRANT OPTION

La clause WITH GRANT OPTION permet à un utilisateur d'accorder ses propres privilèges à d'autres utilisateurs. Cela peut représenter un risque de sécurité important si elle est accordée à des utilisateurs non fiables. Utilisez-la avec parcimonie et uniquement pour les comptes administratifs qui en ont réellement besoin.

-- Un utilisateur avec la capacité d'accorder des privilèges (à utiliser avec une extrême prudence)
CREATE USER 'superadmin'@'localhost' IDENTIFIED BY 'SuperAdminPass!';
GRANT ALL PRIVILEGES ON *.* TO 'superadmin'@'localhost' WITH GRANT OPTION;

2. Sécurité réseau : isoler votre base de données

Les contrôles au niveau réseau sont essentiels pour empêcher tout accès externe non autorisé à votre serveur MySQL.

Configurer les pare-feux

Autorisez les connexions au port par défaut de MySQL (3306) uniquement à partir d'adresses IP ou de réseaux de confiance. Bloquez toutes les autres connexions entrantes vers ce port.

Exemple (UFW sur Linux) :

sudo ufw enable
sudo ufw allow from 192.168.1.0/24 to any port 3306
sudo ufw deny 3306
sudo ufw status

Exemple (CentOS/RHEL avec firewalld) :

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port port="3306" protocol="tcp" accept'
sudo firewall-cmd --permanent --remove-port=3306/tcp --zone=public # Assurez-vous qu'il n'est pas ouvert globalement
sudo firewall-cmd --reload

Sécuriser les connexions avec SSL/TLS

Chiffrez tout le trafic entre les clients et le serveur MySQL à l'aide de SSL/TLS pour empêcher les écoutes clandestines et les attaques de l'homme du milieu (MitM). Ceci est particulièrement crucial pour les connexions sur des réseaux non fiables.

Pour activer SSL/TLS, vous devez généralement générer des certificats et des clés SSL, puis configurer votre my.cnf :

# my.cnf
[mysqld]
ssl_ca=/etc/mysql/certs/ca.pem
ssl_cert=/etc/mysql/certs/server-cert.pem
ssl_key=/etc/mysql/certs/server-key.pem

Les clients doivent ensuite être configurés pour se connecter en utilisant SSL/TLS, souvent avec REQUIRE SSL dans l'instruction GRANT de l'utilisateur :

CREATE USER 'ssl_user'@'%' IDENTIFIED BY 'SSLUserPass!';
GRANT SELECT ON `your_database`.* TO 'ssl_user'@'%' REQUIRE SSL;

Lier à des adresses IP spécifiques

Par défaut, MySQL peut écouter sur toutes les interfaces réseau disponibles (0.0.0.0). Limitez-le pour qu'il écoute uniquement sur les interfaces qui doivent accepter les connexions (par exemple, localhost pour les applications locales, ou une IP réseau privée pour les connexions internes).

# my.cnf
[mysqld]
bind-address = 127.0.0.1  # Pour les connexions locales uniquement
# OU
bind-address = 192.168.1.10  # Pour une IP interne spécifique

Astuce : Si votre application et votre serveur MySQL sont sur la même machine, bind-address = 127.0.0.1 (localhost) est l'option la plus sécurisée, car elle empêche toute connexion externe.

3. Durcissement du fichier de configuration (my.cnf / my.ini)

Le fichier de configuration MySQL (my.cnf sur Linux, my.ini sur Windows) offre de nombreux paramètres pour améliorer la sécurité.

Désactiver les fonctionnalités inutilisées

Minimisez la surface d'attaque en désactivant les fonctionnalités non requises pour votre déploiement.

  • local_infile = 0 : Désactive LOAD DATA LOCAL INFILE, qui peut autrement lire des fichiers depuis l'hôte client lorsque le client et le serveur le permettent.
    [mysqld]
    local_infile = 0
    
  • skip-networking : Si votre base de données n'est accessible que par des applications sur le même serveur, désactivez complètement la mise en réseau. Cela force toutes les connexions à utiliser le socket Unix ou les tubes nommés.
    [mysqld]
    skip-networking
    
  • symbolic-links = 0 : Empêche l'utilisation de liens symboliques pour les tablespaces de base de données, qui peuvent être exploités pour accéder à des fichiers en dehors du répertoire de données MySQL.
    [mysqld]
    symbolic-links = 0
    
  • secure_file_priv : Restreint le répertoire utilisé par les opérations d'importation et d'exportation de fichiers telles que LOAD DATA INFILE et SELECT ... INTO OUTFILE.
    [mysqld]
    secure_file_priv = /var/lib/mysql-files
    

Définissez secure_file_priv sur un répertoire dédié appartenant au compte de service MySQL. Ne le pointez pas vers /tmp, un répertoire de téléchargement d'application ou un chemin auquel des utilisateurs non fiables peuvent écrire.

Éviter les secrets en texte clair dans les fichiers d'options

Les fichiers d'options clients peuvent accidentellement exposer les mots de passe de base de données à quiconque peut les lire. Si vous devez stocker des informations d'identification pour l'automatisation, restreignez les permissions du fichier et utilisez un compte dédié à faibles privilèges.

chmod 600 /home/backup/.my.cnf
chown backup:backup /home/backup/.my.cnf

Pour l'administration interactive, préférez demander le mot de passe :

mysql -u admin -p

4. Mettre à jour et vérifier le serveur

La configuration de sécurité ne sauvera pas un serveur non corrigé. Maintenez MySQL, les bibliothèques clientes et le système d'exploitation à jour via votre processus normal de mise à jour des paquets ou du fournisseur.

Après avoir modifié my.cnf, validez et redémarrez pendant une fenêtre de maintenance :

mysqld --validate-config
sudo systemctl restart mysql
sudo systemctl status mysql

Les noms des paquets et des services varient selon la distribution. Certains systèmes utilisent mysqld au lieu de mysql.

5. Surveiller les accès et examiner les privilèges

Le durcissement n'est pas terminé après le premier passage. Examinez régulièrement les comptes et les autorisations, surtout après des changements d'application ou des départs de personnel.

SELECT user, host, account_locked FROM mysql.user ORDER BY user, host;
SHOW GRANTS FOR 'my_app_user'@'localhost';

Surveillez les comptes qui utilisent des hôtes %, des privilèges larges *.*, FILE, SUPER, SYSTEM_USER ou WITH GRANT OPTION. Ces privilèges peuvent être valides pour un petit nombre de comptes administratifs, mais ils ne devraient jamais apparaître sur des utilisateurs d'application courants.

À retenir

Renforcez MySQL par couches. Commencez par des utilisateurs dédiés à privilèges minimaux, restreignez d'où ils peuvent se connecter, chiffrez le trafic lorsqu'il traverse un réseau, désactivez les fonctionnalités risquées que vous n'utilisez pas et maintenez le serveur à jour. Ensuite, planifiez des examens des privilèges pour que les anciens accès ne deviennent pas silencieusement votre prochain incident.