# SSH Login rate limit über iptables

## mkr

Da mir fast jede Nacht irgendwelche Script-Kiddies die Logfiles meines Servers mit fehlgeschlagenen SSH-Logins füllen, möchte ich ein rate limiting einrichten. Nach 3 Versuchen innerhalb einer Minute soll für eine Minute Schluss sein. Da SSH das nicht unterstützt, habe ich eine Lösung über iptables gefunden. Werden innerhalb einer Minute mehr als 3 Verbindungen von der gleichen IP auf Port 22 aufgebaut, wird die IP für eine Minute gesperrt.

Dazu habe ich mir folgendes Script geschrieben:

iptables -F INPUT

iptables -A INPUT -p tcp --dport 22 -i eth0 -m state --state NEW -m recent --set iptables -A INPUT -p tcp --dport 22 -i eth0 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j LOG --log-prefix "SSH_brute_force "

iptables -A INPUT -p tcp --dport 22 -i eth0 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j REJECT

Am Anfang hat das gut funktioniert, aber am nächsten Tag konnte ich mich nicht mehr einloggen. Jeder Login-Versuch, egal von welcher IP, wurde als "Attacke" gewertet. Auch wenn ich das Script erneut ausführe, was ja die Regeln löscht und neu erstellt, funktioniert kein Login mehr.

Vielleicht würde es wieder für ein paar Stunden gehen, wenn ich den Server neu starten würde, das konnte ich jedoch noch nicht probieren.

Kennt jemand das Problem?

P.S.: Ich weiss, dass ein rate limit die Sicherheit nicht erhöht. Bessere Lösungen wie certificate based authorisation kann ich jedoch nicht umsetzen, da sich verschiedene Leute von immer wieder anderen Rechnern einloggen müssen.

----------

## SinoTech

Hmm .. bin leider auch kein Fachman was "iptables" angeht, aber denke mal bei dir müsste da noch eine "ACCEPT" Regel rein.

Bei mir sieht das in etwa so aus:

```

$IPTABLES -A ssh_chain -p tcp --syn -m recent --name ssh_try --update --seconds 10 -j REJECT --reject-with tcp-reset

$IPTABLES -A ssh_chain -p tcp --syn -m recent --name ssh_try --remove -j ACCEPT

$IPTABLES -A ssh_chain -p tcp --syn -m recent --name ssh_try --set -j ACCEPT

```

Wobei anfangs 2 Verbindungen direkt hintereinander angenommen werden, danach müssen mind. 10 Sekunden vor der nächsten Verbindung liegen. Das Script ist zwar nicht perfekt, aber habe seitdem keine Probleme mehr mit den Loginversuchen  :Very Happy: .

Mfg

Sino

----------

## mkr

 *SinoTech wrote:*   

> Hmm .. bin leider auch kein Fachman was "iptables" angeht, aber denke mal bei dir müsste da noch eine "ACCEPT" Regel rein.

 

Sollte eigentlich nicht notwendig sein, da ich keine andere iptables-Regeln verwende (also auch kein default REJECT). Habs aber trotzdem mal mit einer am Schluss angefügten ACCEPT-Regel probiert, leider ohne Erfolg.

----------

## tango

```
LoginGraceTime 1m

PermitRootLogin no

StrictModes yes

MaxAuthTries 2
```

Sollte doch von ssh Seite auch funktionieren, wenn du ssh dazu noch auf einen anderen Port legst sollte es genügen...

tango

----------

## think4urs11

 *tango wrote:*   

> 
> 
> ```
> LoginGraceTime 1m
> 
> ...

 

Das fängt doch aber nicht das blinde User-ID raten ab, oder?

die grace time sagt doch nur wie lange jemand benötigen darf bis er sein Passwort eingetippt hat.

Trotzdem könnte also noch von außen jemand versuchen mit 1000 verschiedenen Usern 'anzuklopfen'.

Wobei ich nicht vollständig nachvollziehen kann wieso Publickey nicht gehen sollte; schließlich kann man seinen Key ja problemlos auf einem USB-Stick etc. mit sich herumtragen.

----------

## Deever

Leute, hört doch mal mit dem "SSH auf einen anderen Port legen" und iptables-Gefrickel auf! Benutzt Public-Key-Authentication, filtert Passwort-Logins (im Syslog) und gut ist!

SCNR && HTH!,

/dev

----------

## mkr

 *Deever wrote:*   

> Leute, hört doch mal mit dem "SSH auf einen anderen Port legen" und iptables-Gefrickel auf! Benutzt Public-Key-Authentication, filtert Passwort-Logins (im Syslog) und gut ist!

 

Wenn man der einzige ist, der sich über SSH einloggen will: ACK. Der Server steht jedoch auch anderen Usern zur Verfügung, die sich einloggen können sollen. Da ist Public-Key einfach zu umständlich. (Ein klassisches Beispiel von Security vs. Usability.)

Nun denn, ich bin erstaunt, dass die Lösung mit iptables nicht funktioniert, denn sie wird auf vielen Sites empfohlen.

----------

## think4urs11

 *mkr wrote:*   

> .... Der Server steht jedoch auch anderen Usern zur Verfügung, die sich einloggen können sollen. Da ist Public-Key einfach zu umständlich. (Ein klassisches Beispiel von Security vs. Usability.)...

 

Security is always a trade-off with usability

Was ist umständlicher

a) jedem User sein Passwort mitteilen und den SSH-Server mit iptables-voodoo abzusichern versuchen, einen non-standard Port benutzen etc.

b) jedem User einen Key generieren und zukommen lassen den dieser dann verwenden kann wie und wo er möchte (Internetcafe vielleicht ausgenommen)

Ob ein User nun ein schwaches Passwort benutzt bzw. den Spickzettel auf den Bildschirm klebt oder seinen Key ohne Passphrase überall liegenläßt macht keinen großen Unterschied. Beides wirst du nie verhindern können.

Was du aber tun kannst ist den Server mit einfachsten Mitteln sichermachen und die derzeit einfachste Lösung heißt nunmal keine password-auth mehr nutzen.

----------

## mkr

Ich habe in einer Newsgroup einen guten Tipp bekommen: Ein Script, welches das SSH-Logfile überwacht und bei fehlgeschlagenen Logins eine iptables-Regel erstellt, mit der Zugriffe von der IP verboten werden.

Das Tool swatch (http://swatch.sourceforge.net/) macht genau das. Es gibt sogar eine Anleitung dafür im Gentoo Wiki:

http://gentoo-wiki.com/HOWTO_Protect_SSHD_with_Swatch

Leider funktioniert wie im Wiki beschrieben die threshold-Funktion nicht. Bei falschen Usernamen wird der Zugriff also sofort gesperrt. Ohne whitelist (in diesem Fall mein lokales Netz) also nicht zu empfehlen...

----------

## SinoTech

 *mkr wrote:*   

> 
> 
> [...]
> 
> Leider funktioniert wie im Wiki beschrieben die threshold-Funktion nicht. Bei falschen Usernamen wird der Zugriff also sofort gesperrt. Ohne whitelist (in diesem Fall mein lokales Netz) also nicht zu empfehlen...

 

Gibt aber, wie im Wiki beschrieben, immer noch die "ignore Funktion

```

ignore /216\.239\.37\./

```

Mfg

Sino

----------

## mkr

 *SinoTech wrote:*   

> Gibt aber, wie im Wiki beschrieben, immer noch die "ignore Funktion

 

Ja, die verwende ich auch. Aber zusätzlich noch eine iptables-whitelist fand ich keine schlechte Idee.

Das Tool ist aber bestimmt nicht der Weisheit letzter Schluss. Wenn ich mal von extern auf den Server will und mich beim Usernamen vertippe, kann ich SSH von dieser IP aus vergessen, bis ich die Regel von Hand entfernt habe.

----------

## SinoTech

Stimmt, von ausserhalb hättest ein Problem.

Du könntest dir ja aber auch einen PublicKey machen und die Passwort Lösung nur für den Notfall verwenden (Falls du mal den USB-Stick mit dem Key vergisst oder so).

Die extremste Lösung wäre natürlich die, das du dir ein eigenes Programm schreibst das die Anfragen auf dem SSH Port regelt (iptables kann Anfragen auch an den Userspace weiterleiten). Falls es nur für SSH wäre, sollte das Programm sogar sehr klein sein ... aber habe das noch nie probiert ... evtl. mal bei Gelegeneheit  :Very Happy:  ?.

Mfg

Sino

----------

## mkr

Das Problem mit den iptables-recent-rules könnte ein Fehler in iptables sein:

http://www.ussg.iu.edu/hypermail/linux/kernel/0505.1/0190.html

Werde den Patch bei Gelegenheit mal einspielen. Ich wurde aber noch auf ein generelles Problem der recent-rules aufmerksam gemacht: scp öffnet für jede Datei eine neue Verbindung. Bei meinen rules wäre also nach 3 kopierten Dateien Schluss. Nicht wirklich, was man will...

Habe noch etwas anderes spannendes gefunden: ein PAM-Modul für one time passwords:

http://www.cl.cam.ac.uk/~mgk25/otpw.html

Bringt nichts gegen SSH Scanning, erhöht aber die Sicherheit, wenn man sich von nicht vertrauenswürdigen Terminals einloggen muss.

----------

## AntonWert

habe nun auch einmal das so oft diskutierte "skript" ausprobiert und diese Regeln bei iptables eingetragen, leider geht nix  :Sad: 

hier mein Skript:

```

-A INPUT -p tcp dport 22 -m state state NEW -m recent set name SSH

-A INPUT -p tcp dport 22 -m state state NEW -m recent update seconds 60 hitcount 4 rttl name SSH -j LOG log-prefix SSH_brute_force 

-A INPUT -p tcp dport 22 -m state state NEW -m recent update seconds 60 hitcount 4 rttl name SSH -j DROP

-A INPUT -p tcp dport 22 -m state state NEW -j ACCEPT 

```

natürlich habe ich zuvor meine bisherige input-Regel gelöscht... Leider nimmt er immernoch alle Verbindungen an

----------

## AntonWert

kann mir hier keiner helfen?

----------

