Supprimer une clé SSH de ses hôtes connus

J’ai profité de mes récentes migrations de serveur pour re-générer des clés SSH toutes neuves. Je ne pense pas avoir été piraté ni visité depuis que je tiens ce blog mais de temps en temps, une petite remise à frais de la sécurité ne fait pas de mal.

Remise à frais de la sécurité implique que tous mes shells, qui avaient enregistrés l’ancienne clé SSH, détectaient une modification et pensaient à un piratage. Il fallait donc enlever l’ancienne clé de la base des hôtes connus.

On peut faire ça manuellement en modifiant le fichier ~/.ssh/known_hosts mais il faut être sûr de soi quant-à la ligne que l’on enlève. Pas toujours évident.

La manière la plus simple est la commande :

ssh-keygen -f "/home/<USERNAME>/.ssh/known_hosts" -R <NOM_DU_DOMAINE_OU_ADRESSE_MACHINE>

qui se charge d’enlever la clé SSH correspondante à la machine que l’on vise sans risquer d’enlever la mauvaise clé. Il ne reste plus qu’à se connecter de nouveau et les nouvelles informations de connexion seront ajoutées à la liste des hôtes connus.

Hasher une chaîne de caractères en Java

Une notion élémentaire de sécurité informatique est de ne jamais stocker un mot de passe en clair. La moindre brèche de sécurité qui donnerait accès à la base de stockage des comptes utilisateurs aurait des conséquences catastrophiques.

Pour éviter un tel problème, on prend l’habitude systématique de hasher les mots de passe. On prend aussi l’habitude de faire ce que l’on appelle « saler » les mots de passe mais je reviendrai là dessus à la fin.

En Java, le code suivant retourne le hash sous la forme d’un tableau de byte. Son avantage est de ne pas se limiter au seul hash MD5.

public byte[] hasher(String toHash, String algorythm) {
	byte[] hash = null;

    try {
    	hash = MessageDigest.getInstance(algorythm).digest(toHash.getBytes());
    } catch (NoSuchAlgorithmException ex) {
    	Logger.getLogger(Hasher.class.getName()).log(Level.SEVERE, null, ex);
    }

    return hash;
}

Le hash MD5 produit un résultat sur 128 bits. Il est le plus souvent écrit comme une suite de 32 caractères hexadécimaux. Cependant, grâce à ce code, on peut aussi hasher des chaines en SHA-1, SHA-256, …

Il existe plusieurs manières de transformer ce tableau de byte en chaîne de caractères lisible. La plus simple que j’ai trouvé est celle ci :

public String toReadable(byte[] hash) {
    StringBuilder stringBuilder = new StringBuilder();
    for (byte byt : hash) {
        String hex = Integer.toHexString(byt);
        if (hex.length() == 1) {
            stringBuilder.append(0);
            stringBuilder.append(hex.charAt(hex.length() - 1));
        } else {
            stringBuilder.append(hex.substring(hex.length() - 2));
        }
    }
    return stringBuilder.toString();
}

On obtient ainsi un hash de n’importe quelle chaîne, et ce, dans l’algorithme que l’on souhaite.

Maintenant, je vais vous expliquer ce que l’on appelle le sel (salt) et quel est son intérêt.

Un sel est une séquence de bits dont le but est de modifier une séquence originel, dans notre cas, un mot de passe. La séquence peut être aléatoire ou choisie, mise avant ou après, voire même imbriquée. Le but de ce sel est de rendre unique la séquence finale afin de compliquer la tâche d’un attaquant éventuel. Le sel contre particulièrement bien les attaques que l’on appelle attaque par dictionnaire en diminuant les chances que la chaîne se trouve dans l’un d’entre eux.

De plus, même si le hash final ainsi que le sel sont trouvés, il faudrait générer un dictionnaire par sel. Autant dire une tâche longue et fastidieuse à laquelle aucun attaquant ne se lance tellement sa rentabilité est faible.

Supprimer un utilisateur sous MySQL

Par soucis de sécurité, je créé systématiquement un utilisateur différent pour chaque base de données que je créé. Ceci me permet de limiter la casse en cas de piratage ou même d’erreur de ma part. Cela implique aussi que je dois supprimer l’utilisateur d’une base en même temps que la base en elle même puisque ce dernier ne servirait alors plus à rien.

La documentation officielle de MySQL indique que, depuis le version 4.1.1, la fonction

DROP USER <USERNAME>;

a été intégrée. Cependant, celle ci ne supprime que les utilisateurs sans droit. Pour supprimer tous les droits d’un utilisateur, il nous est dit qu’il faut utiliser la commande

REVOKE ALL PRIVILEGES, GRANT OPTION FROM <USERNAME>;

Je ne sais pas à quoi ceci peut être dû mais la commande a refuser de fonctionner pour l’utilisateur que je voulais supprimer. J’ai donc utiliser l’ancienne méthode, efficace même avec les anciennes version de MySQL, la commande :

DELETE FROM mysql.user WHERE user='<USERNAME>';

Désactiver la commande sudo

Pour l’administration de mes serveurs, afin d’éviter tout risque de piratage, il est nécessaire d’avoir 2 mots de passe pour effectuer des commandes root.

Imaginons que notre compte utilisateur a accès à la fonction sudo, comme c’est le cas du première utilisateur créé dans la plupart des distributions GNU/Linux, et que le mot de passe de connexion en SSH est le mot de passe de ce compte. Si quelqu’un arrive à prendre connaissance du mot de passe lors de la connexion (keylogger, regard indiscret, …), il pourra ensuite se reconnecter et avoir un contrôle total du serveur distant.

Afin d’éviter cela, nous allons désactiver la fonction sudo pour l’utilisateur en question. Ainsi, pour effectuer des commandes administrateurs, il faudra se connecter préalablement en tant que super utilisateur.

On changera aussi le mot de passe du super utilisateur pour qu’il soit différent de celui du compte de l’utilisateur, sinon ceci n’a aucun intérêt.

Pour changer le mot de passe de root, rien de plus simple :

  • Si il a déjà été fixé, il suffit de faire
su
passwd

et de taper son nouveau mot de passe.

  • Si il n’a jamais été fixé, il faut se connecter avec un utilisateur possédant le droit d’utilisation de la fonction sudo et faire :
sudo su
passwd

et de taper le nouveau mot de passe.

Maintenant que nous sommes sûr d’avoir un utilisateur root avec un mot de passe que l’on connait, on va désactiver la fonction sudo. Pour ceci plusieurs possibilités :

  • Désinstaller purement et simplement la fonction sudo avec :
apt-get purge sudo
  • Modifier le fichier /etc/sudoers et commenter/supprimer les lignes correspondantes aux utilisateurs. Vous pouvez choisir de laisser ou d’enlever root du fichier. L’intérêt de le laisser est de na pas avoir une erreur lorsque, machinalement, on tape sudo alors qu’on est connecté en root. L’enlever vous forcera à bien séparer les commandes administrateurs des commandes utilisateur dans votre tête. Une autre solution pour se forcer est de retirer la commande sudo du path de l’utilisateur root. Ne connaissant plus la commande sudo, il indiquera systématiquement une erreur.

Il ne reste plus qu’à valider les changements soit en redémarrant la machine, soit à l’aide de la commande :

/etc/init.d/sudo restart

Différentes manières de désactiver l’indexage des dossiers dans Apache2

Dans les dossiers de site internet, Apache va chercher à ouvrir les fichiers qui ont été configurés par défaut (la plupart du temps ce sera index.html ou index.php). Si ces derniers ne figurent pas, Apache va faire un listing des fichiers/dossiers qui sont présents. Ceci peut être particulièrement dangereux si vous possédez des fichiers personnels que vous ne souhaitiez pas partager ou si une personne malveillante s’en sert pour repérer l’arborescence du site et pour repérer les pages d’administrations par exemple.

Il existe plusieurs manières de désactiver ce listage par défaut :

1/ La première consiste, à modifier le fichier de configuration globale d’Apache ou des Virtual Hosts indépendamment en indiquant l’option :

Options -Indexes

On pourra aussi ajouter l’option -FollowSymLinks pour désactiver le suivi des liens symboliques.

2/ La deuxième consiste, si la directive AllowOverride Indexes ou AllowOverride All est activée, à rajouter :

Options -Indexes

dans le fichier .htaccess du répertoire qui ne doit pas afficher l’index. Elle s’appliquera récursivement à tous les sous-dossiers.

3/ Enfin, la dernière solution consiste à désactiver le module autoindex d’apache. Pour ce faire on peut procéder en commentant la ligne

LoadModule autoindex_module modules/mod_autoindex.so

dans le fichier httpd.conf. ou alors en désactivant en ligne de commande le module en tapant :

a2dismod autoindex

Autoriser la connexion de root en FTP avec vsFTPd

ATTENTION : Ce que je détail ici est à titre informatif et n’est en aucun cas recommandé.

Le cas m’est arrivé une fois où je devais me connecter en root en FTP car je n’avais pas encore créé d’autre utilisateur. Ceci est à éviter autant que possible pour plusieurs raison :

  • La première est le fait que le protocole FTP utilisé sans SSL (FTPS) fait transiter en clair les informations de connexion. Ainsi, une personne qui intercepte le mot de passe root peut prendre un accès total de la machine.
  • La deuxième est que, selon moi, le root est l’administrateur de la machine et pas de chaque logiciel.

vsFTPd utilise un fichier qui contient la liste des utilisateurs n’ayant pas le droit de se connecter. Celui ci est /etc/ftpusers. On voit en première ligne que le nom de root y est apposé. Il suffit de supprimer la ligne correspondante et de redémarrer vsFTPd avec

/etc/init.d/vsftpd restart

pour que l’utilisateur root soit autorisé à se connecter.

Installation d’un serveur web sous Debian

J’avais lors d’un précédent post, expliqué comment installer WordPress sur son serveur Web mais je n’avais pas expliqué comment installer ce serveur.

On partira donc du principe que l’on a besoin de mettre en place un serveur HTTP, un interpréteur PHP, un SGBD (Système de Gestion de Base de Données) et un serveur FTP. De plus pour le contrôler facilement à distance on utilisera le protocole SSH.

Tout d’abord le choix de la distribution. Ayant toujours utilisé des distributions basées sur Debian et Debian étant réputé pour sa stabilité, il m’a semblé évident de prendre cette distribution comme base. De plus les installations sont facilitées grâce à des dépôts bien remplis (pas toujours à jour, mais fournis).

Ainsi, après une installation standard de cette distribution, enfin, en tout cas sans gestionnaire de fenêtre vu que c’est pour un serveur, nous allons passer à la phase d’installation.

Les logiciels que j’ai choisis d’utiliser pour combler tous nos besoins sont :

  • Serveur HTTP : Apache
  • Serveur FTP : vsFTPd
  • Serveur SSH : openSSH
  • interpréteur PHP : PHP5
  • SGBD : MySQL

Nous allons commencer par installer openSSH afin de pouvoir administrer le serveur à distance par la suite à l’aide de la commande :

apt-get install ssh

Nous verrons les configurations à apporter à chaque logiciel par la suite. Installons maintenant le serveur Apache à l’aide de la commande :

apt-get install apache2

Puis PHP et son module pour apache en tapant :

apt-get install php5 libapache2-mod-php5

Pour MySQL, Debian se charge normalement tout seul de récupérer les paquets qui permettent les interactions avec PHP. Dans le cas contraire il faudra les rajouter en plus (paquet php5-mysql). On tapera donc :

apt-get install mysql-server

Un mot de passe root est demandé à ce moment là. Bien penser à en mettre un fort.

Nous allons enfin installer vsFTPd en tapant :

apt-get install vsftpd

Maintenant que tous les logiciels dont nous avons besoin sont installés, il va nous falloir les configurer. Toujours garder en tête cependant que les configurations sont la partie la plus personnelle de ce genre de mise en place car elles dépendent principalement de ce que l’on désire faire. Je ne détaillerais pas les configurations d’SSH car j’ai déjà mis un exemple détaillé dans ce post ci.

Commençons donc avec la configuration d’Apache. Un fichier de configuration extrêmement important est le fichier /etc/apache2/conf.d/security. C’est ce fichier qui déterminera le niveau de détail des messages d’erreur. Pour un serveur en production, afin d’éviter toute fuite d’information sensible en cas de faille, on mettra les lignes :

ServerTokens Prod
ServerSignature Off
TraceEnable Off

Pour un serveur de développement, le but étant d’obtenir un maximum d’informations, on mettra :

ServerTokens Full
ServerSignature On
TraceEnable Extended

La configuration de base d’Apache donne le dossier /var/www/ comme dossier du site principal. On peut héberger plusieurs sites sur un seul serveur en rajoutant des fichiers de configuration dans le dossier /etc/apache2/sites-available/ (De manière globale, tout fichier présent dans ce dossier est inclus dans le fichier de configuration au lancement d’Apache). Une configuration minimale de site possible est :

<VirtualHost <ADRESSE_DU_SERVEUR>:<PORT_DE_CONNEXION>>
ServerName <NOM_DU_SERVEUR>
ServerAdmin <ADRESSE_DU_WEBMASTER>

DocumentRoot <DOSSIER_DU_SITE>
<Directory <DOSSIER_DU_SITE>>
Options -Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all
</Directory>

CustomLog <URI_DU_FICHIER_DE_LOG> combined
LogLevel warn
</VirtualHost>

Pour plus de détail on peut aller sur la documentation officielle d’Apache sans oublier les conseils sur la sécurité. On pourra, selon la distinction que l’on voudra faire entre les différents sites web (différentes adresses IP, différents ports de connexion), utiliser cette page de documentation ou celle ci pour choisir ses options.
Vous remarquerez le -Indexes qui permet de ne pas lister le contenu d’un dossier lorsque le fichier index.html ou index.php n’existe pas. Pour d’autres options de sécurités on peut aller voir par là.

Il ne reste alors plus qu’à activer le site nouvellement configuré à l’aide de la commande

a2ensite <NOM_DU_FICHIER_DE_CONFIGURATION>

et à redémarrer apache (nous ferons ceci à la fin).

En ce qui concerne PHP, je ne rentrerais pas dans les détails de la configuration car ils sont beaucoup trop dépendants de ce que l’on souhaite mettre en place. De plus, ceux de base conviendront la plupart du temps.

La configuration de MySQL étant plus une configuration par base de données que dans sa globalité, les paramètres originaux feront largement l’affaire. Cependant, il ne faudra pas oublier de créer un nouvel utilisateur pour chaque base afin d’améliorer la sécurité et de ne pas laisser traîner le mot de passe root quelque part. J’avais détaillé le script de création dans mon post sur la mise en place de mon blog.

Il nous reste enfin à configurer vsFTPd. Mon choix s’est porté sur ce logiciel plutôt que sur ProFTP, qui est le plus souvent cité lorsque l’on cherche un serveur FTP, car, notamment, il a été conçu en étant orienté sécurité. Le fichier de configuration est /etc/vsftpd.conf. Il est bien détaillé et facile à paramétrer. On peut choisir de chrooter les utilisateurs, utiliser le serveur en IPv4/IPv6, autoriser l’accès anonyme, etc … J’ai détaillé une des configuration que j’utilise sur l’un de mes serveurs dans ce post.

Il suffit ensuite soit de redémarrer la machine (le plus simple), soit de redémarrer tous les services, après configuration. On peut les relancer un par un à l’aide des commandes :

/etc/init.d/apache restart
/etc/init.d/ssh restart
/etc/init.d/vsftpd restart

On a alors un serveur HTTP/FTP/MySQL/SSH prêt à être utilisé.

Configuration du serveur FTP

Je voulais un serveur FTP pour pouvoir partager des données facilement et surtout pour avoir un espace de stockage accessible depuis n’importe où. Le premier besoin était de transmettre un gros fichier sans être limité par les quotas d’un mail.

Après avoir cherché un peu sur internet, j’ai décidé d’utiliser vsftpd mais d’autres font tout aussi bien l’affaire (proFTPd par exemple). Je l’ai donc installé avec :

apt-get install vsftpd

Je voulais que chaque utilisateur ait un espace qui lui est propre mais aussi un dossier qui serait commun à tous pour faciliter le partage. J’ai modifié le fichier de configuration ainsi :

listen=YES
anonymous_enable=NO
local_enable=YES
write_enable=YES
dirmessage_enable=YES
use_localtime=YES
xferlog_enable=YES
connect_from_port_20=YES
ftpd_banner=Bienvenue sur mon FTP
chroot_local_user=YES
secure_chroot_dir=/var/run/vsftpd/empty
pam_service_name=vsftpd
rsa_cert_file=/etc/ssl/private/vsftpd.pem

Ceci me permet de garder chaque utilisateur dans son dossier avec des droits de lecture et d’écriture.

EDIT : ATTENTION : Ce qui suit est absolument nul, faisable avec des options sur les commandes de base sans avoir besoin de faire des scripts compliqués, sera supprimé dès que je me serais re-penché sur la question et a été supprimé de mon serveur tellement c’est lourd. Last but not least : le dossier de partage ne fonctionne pas. 

Pour le dossier de partage, j’ai utilisé ce que je qualifierais de patch parce que lourd à mettre en place et à maintenir. Je cherche un moyen plus efficace de faire la même chose.J’ai actuellement procédé ainsi :

mkdir /home/partage
groupadd ftpusers
chown root /home/partage
chgrp ftpusers /home/partage

Maintenant, à la création de chaque utilisateur, on le rendra membre du groupe ftpusers, on créera un dossier de partage et on montera /home/partage dedans. En plus, j’ai fait manuellement toutes ces opérations parce que je n’avais pas lu la manpage de useradd. Tout ceci peut donc évidemment être amélioré.

Voici les deux scripts que j’utilise actuellement pour créer et supprimer des utilisateurs :

Création :

#!/bin/sh
group="/etc/group";
fstab="/etc/fstab";

if [ -z $1 ]
 then
		echo "Usage : $0 username";
		echo "This script was designed to add a user and to give him an access to the shared zone";
 else
		useradd $1;
		mkdir -p /home/$1/partage;
		chown -R $1 /home/$1;
		chgrp -R $1 /home/$1;
		chmod 740 /home/$1
		mount --bind /home/partage /home/$1/partage;
		cp $group $group~
		sed -i "/ftpusers*/ s/.*/&amp;,$1/" $group;
		echo "/home/partage\t/home/$1/partage\tnone\tbind,defaults,auto\t0\t0" &gt;&gt; $fstab;
		echo "Initialisation du mot de passe\n";
		passwd $1;
		echo "User $1 created with success";
 fi

Suppression :

#!/bin/sh
fstab="/etc/fstab";

if [ -z $1 ]
then
        echo "Usage : $0 username";
        echo "This script was designed to add a user and to give him an access to the shared zone";
else
        umount /home/$1/partage;
        userdel $1;
        mv /home/$1 /home/archive;
        sed -i "/*$1*/ s/.*//" $fstab;
        sed -i '/^$/d' $fstab;
        echo "User $1 deleted with success";
fi

Je me rend compte en écrivant cet article que je ne supprime pas la ligne correspondante dans fstab.

A la suppression je déplace l’utilisateur dans le dossier archive au cas où il aurait fallut récupérer des données lui appartenant.

Je pense que ce que je veux faire est possible avec des utilisateurs virtuels. Ce sera mon prochain fil de recherche.