Ein weiterer Weg, wie die langsamen password-guesser (nicht brute-force, was mit fail2ban besser abwehrbar wäre) bekämpft werden können: mit der XBL von Spamhaus.
Inspiriert wurde ich von diesem Beitrag auf dronebl.org
Ein paar Stichproben am betroffenen Server ergaben, dass die XBL wesentlich besser passt. Die XBL (Exploits Block List) ist eigentlich zur Spambekämpfung gedacht. Da sie allerdings "gecracktes Zeugs aller Art" enthält, sind durchaus auch die Botnetze der Passwort-Probierer mit dabei.
So bequem wie mit Postfix kann man dnsbl in Dovecot leider nicht verwenden. Der Aufwand ist aber immer noch vertretbar.
Wichtig dabei ist, dass Dovecot tcpwrap unterstützt, was gar nicht so leicht herauszufinden ist.
dovecot --build-options
zeigt es jedenfalls nicht an.
Also ausprobieren in dovecot.conf oder unterhalb von /etc/dovecot/conf.d/:
login_access_sockets = tcpwrap
service tcpwrap {
unix_listener login/tcpwrap {
mode = 0600
user = $default_login_user
}
}
Wenn nach einem Neustart von Dovecot der Dienst wieder hochkommt und nicht ins Logfile gejammert wurde, wird es unterstützt.
Zur Kontrolle - hier sollte der socket liegen (Debian): /var/run/dovecot/login/tcpwrap
Dann folgendes Skript unter /usr/local/bin/checkdnsbl.sh ablegen:
#!/bin/bash
# exit 0 to block ip
# important: dovecot needs tcpwrapper to make use of hosts.deny
DEBUG=0
DBGLOG='/tmp/checkdebug.log'
BL='xbl.spamhaus.org'
if [ $DEBUG -eq 1 ]
then
touch $DBGLOG
echo '-----' >> $DBGLOG
date >> $DBGLOG
fi
if [ -z $1 ]
then
if [ $DEBUG -eq 1 ]
then
echo 'Error: IP argument missing' >> $DBGLOG
fi
exit 1
fi
if [[ $1 =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]
then
if [ $DEBUG -eq 1 ]
then
echo "Looks like IPv4: $1" >> $DBGLOG
fi
else
if [ $DEBUG -eq 1 ]
then
echo "Warning: $1 seems to be no IPv4, exit" >> $DBGLOG
fi
exit 1
fi
IP_REV=$(echo $1 | gawk -F'.' '{print $4"."$3"."$2"."$1}')
RESULT=$(host ${IP_REV}.$BL.)
RECORD=$(echo $RESULT | gawk '{print $NF}')
if [ "$RECORD" == "127.0.0.4" ]
then
if [ $DEBUG -eq 1 ]
then
echo "$1 is listed in $BL, keep out" >> $DBGLOG
fi
exit 0
else
if [ $DEBUG -eq 1 ]
then
echo "$1 not in blacklist, let authenticate" >> $DBGLOG
fi
exit 1
fi
exit 1
Ausführbar machen (755) und testen. Bei Bedarf den debug mode einschalten. Das Skript ist ein schneller Wurf und kann auf alle Fälle noch verbessert werden.
Und schließlich noch /etc/hosts.deny ergänzen:
imap: ALL : aclexec /usr/local/bin/checkdnsbl.sh %a
aclexec führt unser Skript als Kindprozess aus und richtet sich nach dessen exit Status ("0" heißt in diesem Fall true, also blockt).
"%a" ist der Platzhalter für die remote IP.
Vorteil gegenüber der Variante mit pam_geoip: hosts.deny greift vor der Authentifizierung, also auch bei "user unknown" und ist von Dovecots Authentifizierungsmechanismus unabhängig.
Wie weiß man, dass es klappt?
Entweder das Skript vorübergehend im debug mode laufen lassen (DEBUG=1), oder im syslog oder mail.log nachschauen. Dort werden Einträge in der folgenden Form auftauchen:
...dovecot: imap-login: access(tcpwrap): Client refused (rip=X.X.X.X)
Skaliert die Lösung?
Halbwegs gut. Tatsache ist, dass Spamhaus die Abfragen limitiert, allerdings sind sie recht großzügig. Ein lokaler cache wie z.B. dnsmasq kann außerdem helfen, etwaige Spitzen abzufangen.
Auf alle Fälle ist es eine gute Idee, IPs oder Domains von echten Mailusern in die hosts.allow zu stellen, damit die nicht laufend sinnlos geprüft werden.
Varianten:
Beim Schreiben dieses Beitrags hatte ich spontan eine Idee, wie man ohne externen Dienst (dnsbl) auskommt. Ebenfalls mit hosts.deny - aber mit geoiplookup im Skript, das dann einfach alles verweigert (exit 0), was außerhalb der gewünschten Länder liegt. Die Variante ist hier beschrieben.