Identification

Sécurité MySQL : le B.A.-BA

Catégorie : Auto-hébergement

Vérifier et renommer le compte root

En fonction de la manière dont votre instance de MySQL a été installée, il se peut que qu'elle autorise par défaut les connexions root sans mot de passe. Il faut donc vérifier ce point et procéder aux ajustements nécessaires si besoin.

Vérifier le compte root

Commençons par tenter une connexion/déconnexion à l'aide de la commande suivante :

# mysql -u root -e "quit"
# ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)

Si la commande vous renvoie l'erreur ci-dessus, tout vas bien : la connexion root sans mot de passe est refusée par le serveur.

En revanche, si elle s'exécute sans problème il y a DANGER : l'instance de MySQL fonctionne en mode "portes ouvertes".

Pour corriger le tir il faut définir un mot de passe pour root à l'aide de la commande qui suit, dans laquelle {mdp_root} désigne le mot de passe que vous avez préalablement choisi :

# mysql -u root -e "SET PASSWORD FOR 'root'@'localhost'=PASSWORD('{mdp_root}')"

Si cette commande ne retourne pas d'erreur c'est que le mot de passe root a bien été changé ; vous pouvez ré-exécuter la première commande pour vérifier, elle devrait maintenant vous retourner une erreur.

Renommer le compte root

La plupart des attaques ont pour objet de s'emparer des droits du compte root. La parade la plus simple est donc de renommer ce compte. C'est tout bête mais c'est terriblement efficace.

$ mysql -u root -p{mdp_root}
...
mysql> USE mysql;
...
mysql> UPDATE user SET User='{nom_utilisateur}' WHERE User='root';
...
mysql> FLUSH PRIVILEGES;
...
mysql> quit
Bye

Voici (dans l'ordre) les actions effectuées par les commandes ci-dessus :

  1. Connexion au serveur MySQL en tant que super utilisateur,
  2. Sélection de la base de gestion 'mysql',
  3. Mise à jour du nom du super utilisateur,
  4. Rechargement des privilèges,
  5. Déconnexion du serveur.

Pour vérifier que les changements ont bien été pris en compte il suffit de se reconnecter avec le nouvel identifiant :

$ mysql -u {nom_utilisateur} -p{mdp_root}

Si la connexion fonctionne, c'est tout bon.

Controller les accès distants

Si vous ne projettez pas de vous servir de votre instance de MySQL à distance (par ex.: il n'y a que l'instance locale de PHP qui doit s'y connecter), pensez à le spécifier dans le fichier de configuration. Il est en effet possible de limiter les connexion au seul hôte local via la directive bind-address du fichier /etc/mysql/my.cnf :

# nano /etc/mysql/my.cnf
...
[mysqld]
bind-address = 127.0.0.1
...

Pensez ensuite à redémarrer le serveur :

# /etc/init.d/mysql restart 

Faire le ménage dans les comptes

En fonction de la version de MySQL et du paquetage logiciel que vous avez installé, un certain nombre de données inutiles ont peut être été créés. Faisons un peu de ménage :

$ mysql -u {root} -p{mdp_root}
...
mysql> DROP DATABASE test;
...
mysql> USE mysql;
...
mysql> DELETE FROM user WHERE User = '';
...
mysql> DELETE FROM user WHERE User = '{root}' AND Host != 'localhost';
...
mysql> FLUSH PRIVILEGES;
...
mysql> quit
Bye

Voici (dans l'ordre) les actions effectuées par les commandes ci-dessus :

  1. Connexion au serveur MySQL en tant que super utilisateur,
  2. Suppression de la base de données 'test' qui est parfois crée par défaut et qui ne sert à rien,
  3. Sélection de la base de gestion 'mysql',
  4. Suppression des comptes "vides" éventuellement présents dans la base,
  5. Suppression des utilisateurs "root" qui se connecteraient d'un autre endroit que localhost,
  6. Rechargement des privilèges,
  7. Déconnexion du serveur.
Si vous avez impérativement besoin d'un accès root distant il faudra le configurer par la suite, mais je vous déconseille de créer un tel accès.

Masquer les informations sensibles

Désactiver l'historique du client mysql

Par défaut, l'historique du client mysql en ligne de commande est activé.
Cela signifie que toutes les commandes envoyées au serveur via ce client sont conservées en clair dans un fichier texte situé dans le répertoire home de l'utilisateur, noms d'utilisateurs et mots de passe compris ; ce fichier se nomme  .mysql_history.

Afin de résoudre le problème, je vous propose d'ajouter les quelques lignes ci-dessous à la fin de votre fichier /etc/bash.bashrc :

# nano /etc/bash.bashrc
...
MYSQL_HISTFILE=/dev/null
if [ -f /home/${USER}/.mysql_history ]; then
  rm -f /home/${USER}/.mysql_history
fi

Décryptage : La première ligne définit la variable d'environnement MYSQL_HISTORY et la fait pointer sur /dev/null ; par conséquent plus aucune ligne ne sera inscrite dans l'historique. Les trois lignes suivantes nous permettent de nous assurer que l'historique mysql de l'utilisateur courant est bien supprimé. Le fait d'ajouter l'ensemble de ces lignes au fichier /etc/bash.bashrc permet d'impacter l'ensemble des utilisateurs du système.

Remarque : Si vous souhaitez que cette modification soit prise en compte pour votre session en cours, il vous suffit de taper MYSQL_HISTFILE=/dev/null dans une console système, puis de supprimer le fichier cible avec la commande rm -r ~/.mysql_history.

Désactiver la directive local_infile

La commande LOAD DATA LOCAL de MySQL permet de lire des données sur le serveur et/ou de charger un fichier du serveur vers le client. C'est évidement assez problématique dans la mesure ou il est possible de charger n'importe quel fichier du système (genre /etc/passwd). Il vaut donc mieux veiller à ce que cette possibilité soit désactivé, ce qui est d'ailleurs fait par défaut sur certaines versions de MySQL.

La commande LOAD DATA LOCAL est gérée par la directive de configuration local_infile. Voici comment vérifier sa valeur :

$ mysql -u {root} -p{mdp_root}
...
mysql> SHOW GLOBAL VARIABLES LIKE 'local_infile';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| local_infile  | ON    |
+---------------+-------+
1 row in set (0.00 sec)

mysql> quit
Bye

Si comme dans l'exemple ci-dessus la directive local_infile de votre instance vaut ON, il faut la passer à OFF en éditant le fichier de configuration de votre serveur de la manière suivante :

# nano /etc/mysql/my.cnf
...
[mysqld]
local-infile = OFF
...

Une fois la modification enregistrée il faut redémarrer le serveur :

# /etc/init.d/mysql restart