Sicurezza SSH · 14 min read · Jan 10, 2026

Prevenire gli attacchi di dizionario SSH con DenyHosts

Prevenire gli attacchi di dizionario SSH con DenyHosts

Versione 1.0
Autore: Falko Timme
Ultima modifica: 02/07/2006

In questo HowTo mostrerò come installare e configurare DenyHosts. DenyHosts è uno strumento che osserva i tentativi di accesso a SSH e, se trova tentativi di accesso falliti ripetutamente dallo stesso indirizzo IP, DenyHosts blocca ulteriori tentativi di accesso da quell’indirizzo IP inserendolo in /etc/hosts.deny. DenyHosts può essere eseguito da cron o come demone. In questo tutorial eseguirò DenyHosts come demone.

Dal sito web di DenyHosts:

“DenyHosts è uno script destinato ad essere eseguito dagli amministratori di sistema Linux per aiutare a contrastare gli attacchi ai server ssh.

Se hai mai guardato il tuo log ssh (/var/log/secure su Redhat, /var/log/auth.log su Mandrake, ecc…) potresti essere allarmato nel vedere quanti hacker hanno tentato di accedere al tuo server. Speriamo che nessuno di loro abbia avuto successo (ma d’altra parte, come potresti saperlo?). Non sarebbe meglio prevenire automaticamente che quell’attaccante continui a entrare nel tuo sistema?

DenyHosts cerca di affrontare quanto sopra… “

Questo tutorial è basato su un sistema Debian Sarge, tuttavia, dovrebbe applicarsi ad altre distribuzioni con quasi nessuna modifica.

Voglio dire prima che questo non è l’unico modo per impostare un sistema del genere. Ci sono molti modi per raggiungere questo obiettivo, ma questo è il modo che scelgo. Non fornisco alcuna garanzia che questo funzionerà per te!

1 Installazione

DenyHosts è scritto in Python, quindi dobbiamo prima installare Python e anche i file di sviluppo di Python:

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

Poi scarichiamo e installiamo DenyHosts in questo modo:

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

Questo installa DenyHosts in /usr/share/denyhosts.

2 Configurazione

Ora dobbiamo creare il file di configurazione di DenyHosts /usr/share/denyhosts/denyhosts.cfg. Possiamo usare il file di configurazione di esempio /usr/share/denyhosts/denyhosts.cfg-dist per questo:

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

Poi dobbiamo modificare denyhosts.cfg con il nostro editor preferito come vi, per esempio. Il mio appare così:

| ############ QUESTE IMPOSTAZIONI SONO OBBLIGATORIE ############ ######################################################################## # # SECURE_LOG: il file di log che contiene le informazioni di logging di sshd # se non sei sicuro, grep "sshd:" /var/log/* # # Il file da elaborare può essere sovrascritto con l'argomento della riga di comando --file # # Redhat o Fedora Core: #SECURE_LOG = /var/log/secure # # Mandrake, FreeBSD o OpenBSD: SECURE_LOG = /var/log/auth.log # # SuSE: #SECURE_LOG = /var/log/messages # ######################################################################## ######################################################################## # HOSTS_DENY: il file che contiene le informazioni di accesso degli host ristretti # # La maggior parte dei sistemi operativi: HOSTS_DENY = /etc/hosts.deny # # Alcuni BSD (FreeBSD) Unixes: #HOSTS_DENY = /etc/hosts.allow # # Un'altra possibilità (vedi anche l'opzione successiva): #HOSTS_DENY = /etc/hosts.evil ####################################################################### ######################################################################## # PURGE_DENY: rimuove le voci HOSTS_DENY che sono più vecchie di questo tempo # quando DenyHosts viene invocato con il flag --purge # # il formato è: i[dhwmy] # Dove 'i' è un intero (es. 7) # 'm' = minuti # 'h' = ore # 'd' = giorni # 'w' = settimane # 'y' = anni # # mai purgare: PURGE_DENY = # # purgare voci più vecchie di 1 settimana #PURGE_DENY = 1w # # purgare voci più vecchie di 5 giorni #PURGE_DENY = 5d ####################################################################### ####################################################################### # BLOCK_SERVICE: il nome del servizio che dovrebbe essere bloccato in HOSTS_DENY # # man 5 hosts_access per dettagli # # es. sshd: 127.0.0.1 # bloccherà gli accessi sshd da 127.0.0.1 # # Per bloccare tutti i servizi per l'host colpevole: #BLOCK_SERVICE = ALL # Per bloccare solo sshd: BLOCK_SERVICE = sshd # Per registrare solo l'host colpevole e nient'altro (se si utilizza # un file ausiliario per elencare gli host). Riferirsi a: # http://denyhosts.sourceforge.net/faq.html#aux #BLOCK_SERVICE = # ####################################################################### ####################################################################### # # DENY_THRESHOLD_INVALID: blocca ogni host dopo che il numero di tentativi di accesso falliti # ha superato questo valore. Questo valore si applica ai tentativi di accesso # utente non validi (es. account utente inesistenti) # DENY_THRESHOLD_INVALID = 5 # ####################################################################### ####################################################################### # # DENY_THRESHOLD_VALID: blocca ogni host dopo che il numero di # tentativi di accesso falliti ha superato questo valore. Questo valore si applica a # tentativi di accesso utente validi (es. account utente che esistono in /etc/passwd) tranne # per l'utente "root" # DENY_THRESHOLD_VALID = 10 # ####################################################################### ####################################################################### # # DENY_THRESHOLD_ROOT: blocca ogni host dopo che il numero di tentativi di accesso falliti # ha superato questo valore. Questo valore si applica a # tentativi di accesso dell'utente "root" solo. # DENY_THRESHOLD_ROOT = 5 # ####################################################################### ####################################################################### # # WORK_DIR: il percorso che DenyHosts utilizzerà per scrivere i dati # (verrà creato se non esiste già). # # Nota: si consiglia di utilizzare un percorso assoluto # per questo valore (es. /home/foo/denyhosts/data) # WORK_DIR = /usr/share/denyhosts/data # ####################################################################### ####################################################################### # # SUSPICIOUS_LOGIN_REPORT_ALLOWED_HOSTS # # SUSPICIOUS_LOGIN_REPORT_ALLOWED_HOSTS=YES|NO # Se impostato su YES, se un tentativo di accesso sospetto proviene da un host consentito # allora è considerato sospetto. Se questo è NO, allora i logins sospetti # da host consentiti non verranno segnalati. Tutti i logins sospetti da # indirizzi IP che non sono negli host consentiti verranno sempre segnalati. # SUSPICIOUS_LOGIN_REPORT_ALLOWED_HOSTS=YES ###################################################################### ###################################################################### # # HOSTNAME_LOOKUP # # HOSTNAME_LOOKUP=YES|NO # Se impostato su YES, per ogni indirizzo IP segnalato da Denyhosts, # il corrispondente nome host verrà cercato e segnalato anche # (se disponibile). # HOSTNAME_LOOKUP=YES # ###################################################################### ###################################################################### # # LOCK_FILE # # LOCK_FILE=/path/denyhosts # Se questo file esiste quando DenyHosts viene eseguito, allora DenyHosts uscirà # immediatamente. Altrimenti, questo file verrà creato all'invocazione # e cancellato all'uscita. Questo garantisce che solo un'istanza sia # in esecuzione alla volta. # # Redhat/Fedora: #LOCK_FILE = /var/lock/subsys/denyhosts # # Debian LOCK_FILE = /var/run/denyhosts.pid # # Varie #LOCK_FILE = /tmp/denyhosts.lock # ###################################################################### ############ QUESTE IMPOSTAZIONI SONO OPZIONALI ############ ####################################################################### # # ADMIN_EMAIL: se desideri ricevere email riguardo ai nuovi # host ristretti e accessi sospetti, imposta questo indirizzo per # corrispondere al tuo indirizzo email. Se non desideri ricevere questi rapporti # lascia questo campo vuoto (o esegui con l'opzione --noemail) # ADMIN_EMAIL = # ####################################################################### ####################################################################### # SMTP_HOST = localhost SMTP_PORT = 25 SMTP_FROM = DenyHosts SMTP_SUBJECT = DenyHosts Report #SMTP_USERNAME=foo #SMTP_PASSWORD=bar # ####################################################################### ###################################################################### # # ALLOWED_HOSTS_HOSTNAME_LOOKUP # # ALLOWED_HOSTS_HOSTNAME_LOOKUP=YES|NO # Se impostato su YES, per ogni voce nel file WORK_DIR/allowed-hosts, # il nome host verrà cercato. Se le tue versioni di tcp_wrappers # e sshd a volte registrano nomi host oltre agli indirizzi IP # allora potresti voler specificare questa opzione. # #ALLOWED_HOSTS_HOSTNAME_LOOKUP=NO # ###################################################################### ###################################################################### # # AGE_RESET_VALID: Specifica il periodo di tempo tra i tentativi di accesso falliti # che, se superato, comporterà il ripristino del conteggio dei fallimenti per # questo host a 0. Questo valore si applica ai tentativi di accesso # a tutti gli utenti validi (quelli all'interno di /etc/passwd) con # l'eccezione di root. Se non definito, questo conteggio non verrà mai # ripristinato. # # Vedi i commenti nella sezione PURGE_DENY (sopra) # per dettagli su come specificare questo valore o per dettagli completi # riferirsi a: http://denyhosts.sourceforge.net/faq.html#timespec # AGE_RESET_VALID=5d # ###################################################################### ###################################################################### # # AGE_RESET_ROOT: Specifica il periodo di tempo tra i tentativi di accesso falliti # che, se superato, comporterà il ripristino del conteggio dei fallimenti per # questo host a 0. Questo valore si applica a tutti i tentativi di accesso # all'account utente "root". Se non definito, # questo conteggio non verrà mai ripristinato. # # Vedi i commenti nella sezione PURGE_DENY (sopra) # per dettagli su come specificare questo valore o per dettagli completi # riferirsi a: http://denyhosts.sourceforge.net/faq.html#timespec # AGE_RESET_ROOT=25d # ###################################################################### ###################################################################### # # AGE_RESET_INVALID: Specifica il periodo di tempo tra i tentativi di accesso falliti # che, se superato, comporterà il ripristino del conteggio dei fallimenti per # questo host a 0. Questo valore si applica ai tentativi di accesso # effettuati a qualsiasi nome utente non valido (quelli che non appaiono # in /etc/passwd). Se non definito, il conteggio non verrà mai ripristinato. # # Vedi i commenti nella sezione PURGE_DENY (sopra) # per dettagli su come specificare questo valore o per dettagli completi # riferirsi a: http://denyhosts.sourceforge.net/faq.html#timespec # AGE_RESET_INVALID=10d # ###################################################################### ###################################################################### # # PLUGIN_DENY: Se impostato, questo valore dovrebbe puntare a un eseguibile # programma che verrà invocato quando un host viene aggiunto al # file HOSTS_DENY. Questo eseguibile verrà passato l'host # che verrà aggiunto come unico argomento. # #PLUGIN_DENY=/usr/bin/true # ###################################################################### ###################################################################### # # PLUGIN_PURGE: Se impostato, questo valore dovrebbe puntare a un eseguibile # programma che verrà invocato quando un host viene rimosso dal # file HOSTS_DENY. Questo eseguibile verrà passato l'host # che deve essere purgato come unico argomento. # #PLUGIN_PURGE=/usr/bin/true # ###################################################################### ###################################################################### # # USERDEF_FAILED_ENTRY_REGEX: se impostato, questo valore dovrebbe contenere # una espressione regolare che può essere utilizzata per identificare ulteriori # hacker per la tua particolare configurazione ssh. Questa funzionalità # estende le espressioni regolari incorporate che DenyHosts utilizza. # Questo parametro può essere specificato più volte. # Vedi questa voce faq per ulteriori dettagli: # http://denyhosts.sf.net/faq.html#userdef_regex # #USERDEF_FAILED_ENTRY_REGEX= # ###################################################################### ######### QUESTE IMPOSTAZIONI SONO SPECIFICHE PER LA MODALITÀ DEMONE ########## ####################################################################### # # DAEMON_LOG: quando DenyHosts viene eseguito in modalità demone (--daemon flag) # questo è il file di log che DenyHosts utilizza per segnalare il suo stato. # Per disabilitare il logging, lascia vuoto. (il valore predefinito è: /var/log/denyhosts) # DAEMON_LOG = /var/log/denyhosts # # disabilita il logging: #DAEMON_LOG = # ###################################################################### ####################################################################### # # DAEMON_LOG_TIME_FORMAT: quando DenyHosts viene eseguito in modalità demone # (--daemon flag) questo specifica il formato del timestamp dei # messaggi DAEMON_LOG (il valore predefinito è il formato ISO8061: # cioè. 2005-07-22 10:38:01,745) # # per i valori possibili per questo parametro fare riferimento a: man strftime # # Gen 1 13:05:59 #DAEMON_LOG_TIME_FORMAT = %b %d %H:%M:%S # # Gen 1 01:05:59 #DAEMON_LOG_TIME_FORMAT = %b %d %I:%M:%S # ###################################################################### ####################################################################### # # DAEMON_LOG_MESSAGE_FORMAT: quando DenyHosts viene eseguito in modalità demone # (--daemon flag) questo specifica il formato del messaggio di ogni voce registrata. # Per impostazione predefinita viene utilizzato il seguente formato: # # %(asctime)s - %(name)-12s: %(levelname)-8s %(message)s # # Dove la parte "% (asctime)s" viene espansa nel formato # definito da DAEMON_LOG_TIME_FORMAT # # Questa stringa viene passata al costruttore di logging.Formatter di python. # Per dettagli sui possibili tipi di formato si prega di fare riferimento a: # http://docs.python.org/lib/node357.html # # Questo è il predefinito: #DAEMON_LOG_MESSAGE_FORMAT = %(asctime)s - %(name)-12s: %(levelname)-8s %(message)s # ###################################################################### ####################################################################### # # DAEMON_SLEEP: quando DenyHosts viene eseguito in modalità demone (--daemon flag) # questo è l'importo di tempo che DenyHosts dormirà tra il polling # del SECURE_LOG. Vedi i commenti nella sezione PURGE_DENY (sopra) # per dettagli su come specificare questo valore o per dettagli completi # riferirsi a: http://denyhosts.sourceforge.net/faq.html#timespec # DAEMON_SLEEP = 30s # ####################################################################### ####################################################################### # # DAEMON_PURGE: Con quale frequenza DenyHosts, quando eseguito in modalità demone, # eseguirà il meccanismo di purga per scadere le voci vecchie in HOSTS_DENY # Questo non ha effetto se PURGE_DENY è vuoto. # DAEMON_PURGE = 1h # ####################################################################### ######### QUESTE IMPOSTAZIONI SONO SPECIFICHE PER ########## ######### SINCRONIZZAZIONE DEL DEMONE ########## ####################################################################### # # La modalità di sincronizzazione consente al demone DenyHosts la possibilità # di inviare e ricevere periodicamente dati sugli host negati in modo tale che # i demoni DenyHosts in tutto il mondo possano informarsi automaticamente # riguardo agli host vietati. Questa modalità è disabilitata per # impostazione predefinita, devi decommentare SYNC_SERVER per abilitare questa modalità. # # per ulteriori informazioni, si prega di fare riferimento a: # http:/denyhosts.sourceforge.net/faq.html#sync # ####################################################################### ####################################################################### # # SYNC_SERVER: Il server centrale che comunica con i demoni DenyHost # attualmente, denyhosts.net è l'unico server disponibile # tuttavia, in futuro, potrebbe essere possibile per le organizzazioni # installare il proprio server per la sincronizzazione della rete interna # # Per disabilitare la sincronizzazione (il predefinito), non fare nulla. # # Per abilitare la sincronizzazione, devi decommentare la seguente riga: #SYNC_SERVER = http://xmlrpc.denyhosts.net:9911 # ####################################################################### ####################################################################### # # SYNC_INTERVAL: l'intervallo di tempo per eseguire le sincronizzazioni se # SYNC_SERVER è stato decommentato. Il valore predefinito è 1 ora. # #SYNC_INTERVAL = 1h # ####################################################################### ####################################################################### # # SYNC_UPLOAD: consenti al tuo demone DenyHosts di trasmettere gli host che sono # stati negati? Questa opzione si applica solo se SYNC_SERVER è # stato decommentato. # #SYNC_UPLOAD = no # # il predefinito: #SYNC_UPLOAD = yes # ####################################################################### ####################################################################### # # SYNC_DOWNLOAD: consenti al tuo demone DenyHosts di ricevere gli host che sono # stati negati da altri? Questa opzione si applica solo se SYNC_SERVER è # stato decommentato. # #SYNC_DOWNLOAD = no # # il predefinito: #SYNC_DOWNLOAD = yes # ####################################################################### ####################################################################### # # SYNC_DOWNLOAD_THRESHOLD: Se SYNC_DOWNLOAD è abilitato, questo parametro # filtra gli host restituiti a quelli che sono stati bloccati questo numero # di volte da altri. Cioè, se impostato su 1, allora se un singolo DenyHosts # server ha negato un indirizzo IP, allora riceverai l'host negato. # #SYNC_DOWNLOAD_THRESHOLD = 10 # # il predefinito: #SYNC_DOWNLOAD_THRESHOLD = 3 # ####################################################################### |

Assicurati di impostare SECURE_LOG e LOCK_FILE sui valori corretti per la tua distribuzione! Per Debian, questi sono:

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

Poiché vogliamo eseguire DenyHosts come demone, abbiamo bisogno dello script di controllo del demone /usr/share/denyhosts/daemon-control. Ancora una volta, possiamo usare lo script di esempio /usr/share/denyhosts/daemon-control-dist per creare il file necessario:

cp daemon-control-dist daemon-control

Modifica /usr/share/denyhosts/daemon-control e assicurati di impostare i valori corretti per DENYHOSTS_BIN, DENYHOSTS_LOCK e DENYHOSTS_CFG. Per Debian, questi sono:

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

Quindi il mio /usr/share/denyhosts/daemon-control appare così:

| #!/usr/bin/env python # denyhosts Avvia/ferma il demone DenyHosts # # chkconfig: 2345 98 02 # descrizione: Attiva/Disattiva il # demone DenyHosts per bloccare i tentativi ssh # ############################################### ############################################### #### Modifica questi per adattarli alla tua configurazione #### ############################################### DENYHOSTS_BIN = "/usr/bin/denyhosts.py" DENYHOSTS_LOCK = "/var/run/denyhosts.pid" DENYHOSTS_CFG = "/usr/share/denyhosts/denyhosts.cfg" ############################################### #### Non modificare sotto #### ############################################### import os, sys, signal, time STATE_NOT_RUNNING = -1 STATE_LOCK_EXISTS = -2 def usage(): print "Uso: %s {start [args...] | stop | restart [args...] | status | debug | condrestart [args...] }" % sys.argv[0] print print "Per un elenco di 'args' validi fare riferimento a:" 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 "avviando DenyHosts: ", cmd os.system(cmd) def stop(): pid = getpid() if pid >= 0: os.kill(pid, signal.SIGTERM) print "inviato DenyHosts SIGTERM" else: print "DenyHosts non è in esecuzione" def debug(): pid = getpid() if pid >= 0: os.kill(pid, signal.SIGUSR1) print "inviato DenyHosts SIGUSR1" else: print "DenyHosts non è in esecuzione" def status(): pid = getpid() if pid == STATE_LOCK_EXISTS: print "%s esiste ma DenyHosts non è in esecuzione" % DENYHOSTS_LOCK elif pid == STATE_NOT_RUNNING: print "Denyhosts non è in esecuzione" else: print "DenyHosts è in esecuzione con 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() |

Successivamente, dobbiamo rendere quel file eseguibile:

chown root daemon-control
chmod 700 daemon-control

Dopo, creiamo i collegamenti di avvio del sistema per DenyHosts in modo che venga avviato automaticamente all’avvio del sistema:

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

Infine, avviamo DenyHosts:

/etc/init.d/denyhosts start

DenyHosts registra in /var/log/denyhosts, se sei interessato ai log. Il demone SSH registra in /var/log/auth.log su Debian. Puoi guardare entrambi i log e provare a effettuare il login con un utente non valido o con un utente valido e una password errata, ecc. tramite SSH e vedere cosa succede. Dopo aver superato la soglia dei tentativi di accesso errati, l’indirizzo IP da cui hai provato a connetterti dovrebbe essere elencato in /etc/hosts.deny, in questo modo:

| # /etc/hosts.deny: elenco degli host che NON sono autorizzati ad accedere al sistema. # Vedi le pagine manuali hosts_access(5), hosts_options(5) # e /usr/doc/netbase/portmapper.txt.gz # # Esempio: ALL: some.host.name, .some.domain # TUTTI ECCETTO in.fingerd: other.host.name, .other.domain # # Se intendi proteggere il portmapper usa il nome "portmap" per il # nome del demone. Ricorda che puoi usare solo la parola chiave "ALL" e gli indirizzi IP # (NON nomi host o nomi di dominio) per il portmapper. Vedi portmap(8) # e /usr/doc/portmap/portmapper.txt.gz per ulteriori informazioni. # # Il carattere jolly PARANOID corrisponde a qualsiasi host il cui nome non corrisponde al suo # indirizzo. # Potresti voler abilitare questo per garantire che eventuali programmi che non # convalidano i nomi host cercati lascino comunque log comprensibili. Nelle versioni passate # di Debian questo è stato il predefinito. # TUTTI: PARANOID sshd: 192.168.0.203 |

Ciò significa che il sistema con l’indirizzo IP 192.168.0.203 non può più connettersi utilizzando SSH.

Puoi specificare se/quando gli indirizzi IP vengono rimossi nuovamente da /etc/hosts.deny - dai un’occhiata alla variabile PURGE_DENY in /usr/share/denyhosts/denyhosts.cfg. Devi avviare DenyHosts con l’opzione –purge per rendere efficace la variabile PURGE_DENY, in questo modo:

/etc/init.d/denyhosts start –purge

Tuttavia, puoi anche rimuovere manualmente gli indirizzi IP da lì, e non appena sono stati rimossi, questi indirizzi IP possono provare a effettuare il login nuovamente tramite SSH.

Link

Share: X/Twitter LinkedIn

Ricevi i nuovi post nella tua casella di posta.

Nessuno spam. Disiscriviti in qualsiasi momento.