Sécurité SSH · 15 min read · Jan 10, 2026

Prévenir les attaques par dictionnaire SSH avec DenyHosts

Prévenir les attaques par dictionnaire SSH avec DenyHosts

Version 1.0
Auteur : Falko Timme
Dernière modification : 02/07/2006

Dans ce HowTo, je vais montrer comment installer et configurer DenyHosts. DenyHosts est un outil qui observe les tentatives de connexion à SSH, et s’il trouve des tentatives de connexion échouées encore et encore depuis la même adresse IP, DenyHosts bloque d’autres tentatives de connexion depuis cette adresse IP en l’ajoutant à /etc/hosts.deny. DenyHosts peut être exécuté par cron ou en tant que démon. Dans ce tutoriel, je vais exécuter DenyHosts en tant que démon.

Depuis le site web de DenyHosts :

“DenyHosts est un script destiné à être exécuté par les administrateurs système Linux pour aider à contrer les attaques sur les serveurs ssh.

Si vous avez déjà regardé votre journal ssh (/var/log/secure sur Redhat, /var/log/auth.log sur Mandrake, etc…), vous pourriez être alarmé de voir combien de hackers ont tenté d’accéder à votre serveur. Espérons qu’aucun d’eux n’a réussi (mais alors, comment le sauriez-vous ?). Ne serait-il pas mieux d’empêcher automatiquement cet attaquant de continuer à entrer dans votre système ?

DenyHosts tente de répondre à cela… “

Ce tutoriel est basé sur un système Debian Sarge, cependant, il devrait s’appliquer à d’autres distributions avec presque aucune modification.

Je veux d’abord dire que ce n’est pas la seule façon de mettre en place un tel système. Il existe de nombreuses façons d’atteindre cet objectif, mais c’est la méthode que je choisis. Je ne donne aucune garantie que cela fonctionnera pour vous !

1 Installation

DenyHosts est écrit en Python, nous devons donc d’abord installer Python et également les fichiers de développement Python :

apt-get install python python2.3-dev python2.3

Ensuite, nous téléchargeons et installons DenyHosts comme ceci :

cd /tmp
wget http://mesh.dl.sourceforge.net/sourceforge/denyhosts/DenyHosts-2.0.tar.gz
tar xvfz DenyHosts-2.0.tar.gz
cd DenyHosts-2.0
python setup.py install

Cela installe DenyHosts dans /usr/share/denyhosts.

2 Configuration

Maintenant, nous devons créer le fichier de configuration de DenyHosts /usr/share/denyhosts/denyhosts.cfg. Nous pouvons utiliser le fichier de configuration d’exemple /usr/share/denyhosts/denyhosts.cfg-dist pour cela :

cd /usr/share/denyhosts
cp denyhosts.cfg-dist denyhosts.cfg

Ensuite, nous devons éditer denyhosts.cfg avec notre éditeur préféré comme vi, par exemple. Le mien ressemble à ceci :

| ############ CES PARAMÈTRES SONT REQUIS ############ ######################################################################## # # SECURE_LOG : le fichier journal qui contient les informations de journalisation sshd # si vous n'êtes pas sûr, grep "sshd:" /var/log/* # # Le fichier à traiter peut être remplacé par l'argument de ligne de commande --file # # Redhat ou Fedora Core : #SECURE_LOG = /var/log/secure # # Mandrake, FreeBSD ou OpenBSD : SECURE_LOG = /var/log/auth.log # # SuSE : #SECURE_LOG = /var/log/messages # ######################################################################## ######################################################################## # HOSTS_DENY : le fichier qui contient les informations d'accès des hôtes restreints # # La plupart des systèmes d'exploitation : HOSTS_DENY = /etc/hosts.deny # # Certains BSD (FreeBSD) Unixes : #HOSTS_DENY = /etc/hosts.allow # # Une autre possibilité (voir aussi l'option suivante) : #HOSTS_DENY = /etc/hosts.evil ####################################################################### ######################################################################## # PURGE_DENY : supprime les entrées HOSTS_DENY qui sont plus anciennes que ce temps # lorsque DenyHosts est invoqué avec le drapeau --purge # # le format est : i[dhwmy] # Où 'i' est un entier (ex. 7) # 'm' = minutes # 'h' = heures # 'd' = jours # 'w' = semaines # 'y' = années # # jamais purger : PURGE_DENY = # # purger les entrées plus anciennes qu'une semaine #PURGE_DENY = 1w # # purger les entrées plus anciennes que 5 jours #PURGE_DENY = 5d ####################################################################### ####################################################################### # BLOCK_SERVICE : le nom du service qui doit être bloqué dans HOSTS_DENY # # man 5 hosts_access pour plus de détails # # ex. sshd : 127.0.0.1 # bloquera les connexions sshd depuis 127.0.0.1 # # Pour bloquer tous les services pour l'hôte en faute : #BLOCK_SERVICE = ALL # Pour bloquer uniquement sshd : BLOCK_SERVICE = sshd # Pour ne seulement enregistrer l'hôte en faute et rien d'autre (si vous utilisez # un fichier auxiliaire pour lister les hôtes). Référez-vous à : # http://denyhosts.sourceforge.net/faq.html#aux #BLOCK_SERVICE = # ####################################################################### ####################################################################### # # DENY_THRESHOLD_INVALID : bloque chaque hôte après que le nombre de tentatives de connexion échouées # a dépassé cette valeur. Cette valeur s'applique aux tentatives de connexion d'utilisateur invalides # (ex. comptes d'utilisateur inexistants) # DENY_THRESHOLD_INVALID = 5 # ####################################################################### ####################################################################### # # DENY_THRESHOLD_VALID : bloque chaque hôte après que le nombre de tentatives de connexion échouées # a dépassé cette valeur. Cette valeur s'applique aux tentatives de connexion d'utilisateur valides # (ex. comptes d'utilisateur qui existent dans /etc/passwd) sauf # pour l'utilisateur "root" # DENY_THRESHOLD_VALID = 10 # ####################################################################### ####################################################################### # # DENY_THRESHOLD_ROOT : bloque chaque hôte après que le nombre de tentatives de connexion échouées # a dépassé cette valeur. Cette valeur s'applique uniquement aux # tentatives de connexion de l'utilisateur "root". # DENY_THRESHOLD_ROOT = 5 # ####################################################################### ####################################################################### # # WORK_DIR : le chemin que DenyHosts utilisera pour écrire des données # (il sera créé s'il n'existe pas déjà). # # Remarque : il est recommandé d'utiliser un chemin absolu # pour cette valeur (ex. /home/foo/denyhosts/data) # WORK_DIR = /usr/share/denyhosts/data # ####################################################################### ####################################################################### # # SUSPICIOUS_LOGIN_REPORT_ALLOWED_HOSTS # # SUSPICIOUS_LOGIN_REPORT_ALLOWED_HOSTS=OUI|NON # Si défini sur OUI, si une tentative de connexion suspecte provient d'un hôte autorisé # alors elle est considérée comme suspecte. Si c'est NON, alors les connexions suspectes # provenant d'hôtes autorisés ne seront pas signalées. Toutes les connexions suspectes provenant # d'adresses IP qui ne sont pas dans les hôtes autorisés seront toujours signalées. # SUSPICIOUS_LOGIN_REPORT_ALLOWED_HOSTS=OUI ###################################################################### ###################################################################### # # HOSTNAME_LOOKUP # # HOSTNAME_LOOKUP=OUI|NON # Si défini sur OUI, pour chaque adresse IP signalée par Denyhosts, # le nom d'hôte correspondant sera recherché et signalé également # (si disponible). # HOSTNAME_LOOKUP=OUI # ###################################################################### ###################################################################### # # LOCK_FILE # # LOCK_FILE=/path/denyhosts # Si ce fichier existe lorsque DenyHosts est exécuté, alors DenyHosts sortira # immédiatement. Sinon, ce fichier sera créé lors de l'invocation # et supprimé à la sortie. Cela garantit qu'une seule instance est # en cours d'exécution à la fois. # # Redhat/Fedora : #LOCK_FILE = /var/lock/subsys/denyhosts # # Debian LOCK_FILE = /var/run/denyhosts.pid # # Divers #LOCK_FILE = /tmp/denyhosts.lock # ###################################################################### ############ CES PARAMÈTRES SONT OPTIONNELS ############ ####################################################################### # # ADMIN_EMAIL : si vous souhaitez recevoir des e-mails concernant les nouveaux # hôtes restreints et les connexions suspectes, définissez cette adresse pour # correspondre à votre adresse e-mail. Si vous ne souhaitez pas recevoir ces rapports, # laissez ce champ vide (ou exécutez avec l'option --noemail) # ADMIN_EMAIL = # ####################################################################### ####################################################################### # SMTP_HOST = localhost SMTP_PORT = 25 SMTP_FROM = DenyHosts SMTP_SUBJECT = Rapport DenyHosts #SMTP_USERNAME=foo #SMTP_PASSWORD=bar # ####################################################################### ###################################################################### # # ALLOWED_HOSTS_HOSTNAME_LOOKUP # # ALLOWED_HOSTS_HOSTNAME_LOOKUP=OUI|NON # Si défini sur OUI, pour chaque entrée dans le fichier WORK_DIR/allowed-hosts, # le nom d'hôte sera recherché. Si vos versions de tcp_wrappers # et sshd enregistrent parfois des noms d'hôtes en plus des adresses IP, # alors vous souhaiterez peut-être spécifier cette option. # #ALLOWED_HOSTS_HOSTNAME_LOOKUP=NON # ###################################################################### ###################################################################### # # AGE_RESET_VALID : Spécifie la période de temps entre les tentatives de connexion échouées # qui, lorsqu'elle est dépassée, entraînera la réinitialisation du compte échoué pour # cet hôte à 0. Cette valeur s'applique aux tentatives de connexion # à tous les utilisateurs valides (ceux dans /etc/passwd) avec # l'exception de root. Si non défini, ce compte ne sera jamais # réinitialisé. # # Voir les commentaires dans la section PURGE_DENY (ci-dessus) # pour des détails sur la spécification de cette valeur ou pour des détails complets # référez-vous à : http://denyhosts.sourceforge.net/faq.html#timespec # AGE_RESET_VALID=5d # ###################################################################### ###################################################################### # # AGE_RESET_ROOT : Spécifie la période de temps entre les tentatives de connexion échouées # qui, lorsqu'elle est dépassée, entraînera la réinitialisation du compte échoué pour # cet hôte à 0. Cette valeur s'applique à toutes les tentatives de connexion # au compte utilisateur "root". Si non défini, # ce compte ne sera jamais réinitialisé. # # Voir les commentaires dans la section PURGE_DENY (ci-dessus) # pour des détails sur la spécification de cette valeur ou pour des détails complets # référez-vous à : http://denyhosts.sourceforge.net/faq.html#timespec # AGE_RESET_ROOT=25d # ###################################################################### ###################################################################### # # AGE_RESET_INVALID : Spécifie la période de temps entre les tentatives de connexion échouées # qui, lorsqu'elle est dépassée, entraînera la réinitialisation du compte échoué pour # cet hôte à 0. Cette valeur s'applique aux tentatives de connexion # faites à tout nom d'utilisateur invalide (ceux qui n'apparaissent pas # dans /etc/passwd). Si non défini, le compte ne sera jamais réinitialisé. # # Voir les commentaires dans la section PURGE_DENY (ci-dessus) # pour des détails sur la spécification de cette valeur ou pour des détails complets # référez-vous à : http://denyhosts.sourceforge.net/faq.html#timespec # AGE_RESET_INVALID=10d # ###################################################################### ###################################################################### # # PLUGIN_DENY : Si défini, cette valeur doit pointer vers un exécutable # qui sera invoqué lorsqu'un hôte est ajouté au # fichier HOSTS_DENY. Cet exécutable sera passé l'hôte # qui sera ajouté comme seul argument. # #PLUGIN_DENY=/usr/bin/true # ###################################################################### ###################################################################### # # PLUGIN_PURGE : Si défini, cette valeur doit pointer vers un exécutable # qui sera invoqué lorsqu'un hôte est supprimé du # fichier HOSTS_DENY. Cet exécutable sera passé l'hôte # qui doit être purgé comme seul argument. # #PLUGIN_PURGE=/usr/bin/true # ###################################################################### ###################################################################### # # USERDEF_FAILED_ENTRY_REGEX : si défini, cette valeur doit contenir # une expression régulière qui peut être utilisée pour identifier des # hackers supplémentaires pour votre configuration ssh particulière. Cette fonctionnalité # étend les expressions régulières intégrées que DenyHosts utilise. # Ce paramètre peut être spécifié plusieurs fois. # Voir cette entrée de faq pour plus de détails : # http://denyhosts.sf.net/faq.html#userdef_regex # #USERDEF_FAILED_ENTRY_REGEX= # ###################################################################### ######### CES PARAMÈTRES SONT SPÉCIFIQUES AU MODE DAEMON ########## ####################################################################### # # DAEMON_LOG : lorsque DenyHosts est exécuté en mode démon (--daemon flag) # c'est le fichier journal que DenyHosts utilise pour signaler son statut. # Pour désactiver la journalisation, laissez vide. (par défaut : /var/log/denyhosts) # DAEMON_LOG = /var/log/denyhosts # # désactiver la journalisation : #DAEMON_LOG = # ####################################################################### ####################################################################### # # DAEMON_LOG_TIME_FORMAT : lorsque DenyHosts est exécuté en mode démon # (--daemon flag) cela spécifie le format de l'horodatage des # messages DAEMON_LOG (par défaut est le format ISO8061 : # c'est-à-dire 2005-07-22 10:38:01,745) # # pour les valeurs possibles pour ce paramètre, référez-vous à : man strftime # # Jan 1 13:05:59 #DAEMON_LOG_TIME_FORMAT = %b %d %H:%M:%S # # Jan 1 01:05:59 #DAEMON_LOG_TIME_FORMAT = %b %d %I:%M:%S # ###################################################################### ####################################################################### # # DAEMON_LOG_MESSAGE_FORMAT : lorsque DenyHosts est exécuté en mode démon # (--daemon flag) cela spécifie le format du message de chaque entrée journalisée. # Par défaut, le format suivant est utilisé : # # %(asctime)s - %(name)-12s : %(levelname)-8s %(message)s # # Où la portion "%(asctime)s" est développée au format # défini par DAEMON_LOG_TIME_FORMAT # # Cette chaîne est passée au constructeur logging.Formatter de python. # Pour des détails sur les types de format possibles, veuillez vous référer à : # http://docs.python.org/lib/node357.html # # C'est le défaut : #DAEMON_LOG_MESSAGE_FORMAT = %(asctime)s - %(name)-12s : %(levelname)-8s %(message)s # ###################################################################### ####################################################################### # # DAEMON_SLEEP : lorsque DenyHosts est exécuté en mode démon (--daemon flag) # c'est la durée pendant laquelle DenyHosts dormira entre les sondages # du SECURE_LOG. Voir les commentaires dans la section PURGE_DENY (ci-dessus) # pour des détails sur la spécification de cette valeur ou pour des détails complets # référez-vous à : http://denyhosts.sourceforge.net/faq.html#timespec # DAEMON_SLEEP = 30s # ####################################################################### ####################################################################### # # DAEMON_PURGE : À quelle fréquence DenyHosts, lorsqu'il est exécuté en mode démon, # doit-il exécuter le mécanisme de purge pour expirer les anciennes entrées dans HOSTS_DENY # Cela n'a aucun effet si PURGE_DENY est vide. # DAEMON_PURGE = 1h # ####################################################################### ######### CES PARAMÈTRES SONT SPÉCIFIQUES À ########## ######### LA SYNCHRONISATION DU DAEMON ########## ####################################################################### # # Le mode de synchronisation permet au démon DenyHosts d'envoyer et de recevoir périodiquement # des données d'hôtes refusés afin que les démons DenyHosts dans le monde entier puissent # s'informer automatiquement les uns les autres concernant les hôtes bannis. Ce mode est désactivé par # défaut, vous devez décommenter SYNC_SERVER pour activer ce mode. # # pour plus d'informations, veuillez vous référer à : # http:/denyhosts.sourceforge.net/faq.html#sync # ####################################################################### ####################################################################### # # SYNC_SERVER : Le serveur central qui communique avec les démons DenyHost # Actuellement, denyhosts.net est le seul serveur disponible # cependant, à l'avenir, il pourrait être possible pour des organisations de # installer leur propre serveur pour la synchronisation du réseau interne # # Pour désactiver la synchronisation (par défaut), ne rien faire. # # Pour activer la synchronisation, vous devez décommenter la ligne suivante : #SYNC_SERVER = http://xmlrpc.denyhosts.net:9911 # ####################################################################### ####################################################################### # # SYNC_INTERVAL : l'intervalle de temps pour effectuer des synchronisations si # SYNC_SERVER a été décommenté. La valeur par défaut est 1 heure. # #SYNC_INTERVAL = 1h # ####################################################################### ####################################################################### # # SYNC_UPLOAD : autoriser votre démon DenyHosts à transmettre des hôtes qui ont # été refusés ? Cette option ne s'applique que si SYNC_SERVER a # été décommenté. # #SYNC_UPLOAD = non # # la valeur par défaut : #SYNC_UPLOAD = oui # ####################################################################### ####################################################################### # # SYNC_DOWNLOAD : autoriser votre démon DenyHosts à recevoir des hôtes qui ont # été refusés par d'autres ? Cette option ne s'applique que si SYNC_SERVER a # été décommenté. # #SYNC_DOWNLOAD = non # # la valeur par défaut : #SYNC_DOWNLOAD = oui # ####################################################################### ####################################################################### # # SYNC_DOWNLOAD_THRESHOLD : Si SYNC_DOWNLOAD est activé, ce paramètre # filtre les hôtes retournés à ceux qui ont été bloqués ce nombre de # fois par d'autres. C'est-à-dire, si défini sur 1, alors si un seul serveur DenyHosts # a refusé une adresse IP, alors vous recevrez l'hôte refusé. # #SYNC_DOWNLOAD_THRESHOLD = 10 # # la valeur par défaut : #SYNC_DOWNLOAD_THRESHOLD = 3 # ####################################################################### |

Assurez-vous de définir SECURE_LOG et LOCK_FILE sur les valeurs correctes pour votre distribution ! Pour Debian, celles-ci sont :

SECURE_LOG = /var/log/auth.log
LOCK_FILE = /var/run/denyhosts.pid

Comme nous voulons exécuter DenyHosts en tant que démon, nous avons besoin du script de contrôle du démon /usr/share/denyhosts/daemon-control. Encore une fois, nous pouvons utiliser le script d’exemple /usr/share/denyhosts/daemon-control-dist pour créer le fichier nécessaire :

cp daemon-control-dist daemon-control

Éditez /usr/share/denyhosts/daemon-control et assurez-vous de définir les valeurs correctes pour DENYHOSTS_BIN, DENYHOSTS_LOCK et DENYHOSTS_CFG. Pour Debian, celles-ci sont :

DENYHOSTS_BIN = “/usr/bin/denyhosts.py”
DENYHOSTS_LOCK = “/var/run/denyhosts.pid”
DENYHOSTS_CFG = “/usr/share/denyhosts/denyhosts.cfg”

Ainsi, mon /usr/share/denyhosts/daemon-control ressemble à ceci :

| #!/usr/bin/env python # denyhosts Démarrer/arrêter le démon DenyHosts # # chkconfig: 2345 98 02 # description: Active/Désactive le # démon DenyHosts pour bloquer les tentatives ssh # ############################################### ############################################### #### Modifiez ceci pour convenir à votre configuration #### ############################################### DENYHOSTS_BIN = "/usr/bin/denyhosts.py" DENYHOSTS_LOCK = "/var/run/denyhosts.pid" DENYHOSTS_CFG = "/usr/share/denyhosts/denyhosts.cfg" ############################################### #### Ne pas modifier ci-dessous #### ############################################### import os, sys, signal, time STATE_NOT_RUNNING = -1 STATE_LOCK_EXISTS = -2 def usage(): print "Usage: %s {start [args...] | stop | restart [args...] | status | debug | condrestart [args...] }" % sys.argv[0] print print "Pour une liste des 'args' valides, référez-vous à:" print "$ denyhosts.py --help" print sys.exit(0) def getpid(): try: fp = open(DENYHOSTS_LOCK, "r") pid = int(fp.readline().rstrip()) fp.close() except Exception, e: return STATE_NOT_RUNNING if os.access(os.path.join("/proc", str(pid)), os.F_OK): return pid else: return STATE_LOCK_EXISTS def start(*args): cmd = "%s --daemon " % DENYHOSTS_BIN if args: cmd += ' '.join(args) print "démarrage de DenyHosts : ", cmd os.system(cmd) def stop(): pid = getpid() if pid >= 0: os.kill(pid, signal.SIGTERM) print "envoi de SIGTERM à DenyHosts" else: print "DenyHosts n'est pas en cours d'exécution" def debug(): pid = getpid() if pid >= 0: os.kill(pid, signal.SIGUSR1) print "envoi de SIGUSR1 à DenyHosts" else: print "DenyHosts n'est pas en cours d'exécution" def status(): pid = getpid() if pid == STATE_LOCK_EXISTS: print "%s existe mais DenyHosts n'est pas en cours d'exécution" % DENYHOSTS_LOCK elif pid == STATE_NOT_RUNNING: print "Denyhosts n'est pas en cours d'exécution" else: print "DenyHosts est en cours d'exécution avec pid = %d" % pid def condrestart(*args): pid = getpid() if pid >= 0: restart(*args) def restart(*args): stop() time.sleep(1) start(*args) if __name__ == '__main__': cases = {'start': start, 'stop': stop, 'debug': debug, 'status': status, 'condrestart': condrestart, 'restart': restart} try: args = sys.argv[2:] except: args = [] try: option = sys.argv[1] if option in ('start', 'restart', 'condrestart'): if '--config' not in args and '-c' not in args: args.append("--config=%s" % DENYHOSTS_CFG) cmd = cases[option] apply(cmd, args) except: usage() |

Ensuite, nous devons rendre ce fichier exécutable :

chown root daemon-control
chmod 700 daemon-control

Ensuite, nous créons les liens de démarrage du système pour DenyHosts afin qu’il soit démarré automatiquement lorsque le système est démarré :

cd /etc/init.d
ln -s /usr/share/denyhosts/daemon-control denyhosts
update-rc.d denyhosts defaults

Enfin, nous démarrons DenyHosts :

/etc/init.d/denyhosts start

DenyHosts journalise dans /var/log/denyhosts, si vous êtes intéressé par les journaux. Le démon SSH journalise dans /var/log/auth.log sur Debian. Vous pouvez surveiller les deux journaux et essayer de vous connecter avec un utilisateur invalide ou avec un utilisateur valide et un mot de passe incorrect, etc. via SSH et voir ce qui se passe. Après avoir franchi le seuil des tentatives de connexion incorrectes, l’adresse IP depuis laquelle vous avez essayé de vous connecter devrait être répertoriée dans /etc/hosts.deny, comme ceci :

| # /etc/hosts.deny : liste des hôtes qui ne sont _pas_ autorisés à accéder au système. # Voir les pages de manuel hosts_access(5), hosts_options(5) # et /usr/doc/netbase/portmapper.txt.gz # # Exemple : ALL : some.host.name, .some.domain # ALL EXCEPT in.fingerd : other.host.name, .other.domain # # Si vous allez protéger le portmapper, utilisez le nom "portmap" pour le # nom du démon. N'oubliez pas que vous ne pouvez utiliser que le mot-clé "ALL" et les adresses IP # (PAS les noms d'hôtes ou de domaine) pour le portmapper. Voir portmap(8) # et /usr/doc/portmap/portmapper.txt.gz pour plus d'informations. # # Le caractère générique PARANOID correspond à tout hôte dont le nom ne correspond pas à son # adresse. # Vous souhaiterez peut-être activer cela pour garantir que tous les programmes qui ne # valident pas les noms d'hôtes recherchés laissent toujours des journaux compréhensibles. Dans les versions passées # de Debian, cela a été le défaut. # ALL : PARANOID sshd : 192.168.0.203 |

Cela signifie que le système avec l’adresse IP 192.168.0.203 ne peut plus se connecter via SSH.

Vous pouvez spécifier si/quand les adresses IP sont à nouveau supprimées de /etc/hosts.deny - jetez un œil à la variable PURGE_DENY dans /usr/share/denyhosts/denyhosts.cfg. Vous devez démarrer DenyHosts avec l’option –purge pour rendre la variable PURGE_DENY effective, comme ceci :

/etc/init.d/denyhosts start –purge

Cependant, vous pouvez également supprimer manuellement des adresses IP de là, et dès qu’elles ont été supprimées, ces adresses IP peuvent essayer de se connecter à nouveau via SSH.

Liens

Share: X/Twitter LinkedIn

Recevez de nouveaux articles dans votre boîte de réception.

Aucun spam. Désabonnez-vous à tout moment.