SSH-Zugriff verweigert bei externem Zugriff über DynDNS

  • Hallo RaspberrPiForum,


    ich nutze einen RaspberryPi3 mit Raspbian Stretch Lite in meinem Heimnetz (Router: Fritzbox 6490 Cable).

    Ein SSH-Zugriff über beliebige WindowsRechner (Win7, Win10 über Putty) in meinem Heimnetz (private IPv4-Adressen) funktioniert tadelos.


    Für einen externen Zugriff habe ich nun auf meiner o. g. Fritzbox eine Portweiterleitung auf den PI eingerichtet, sowie eine Domain über einen DYNDNS-Service (ddnss.net) eingerichtet.

    Eine Überprüfung der Portweiterleitung mit telnet (telnet xxxxx.dyndns.net 22) führt zu positivem Ergebnis: Es meldet sich OpenSSH unter Angabe der Debian-Distribution.


    fail2ban ist nicht installiert , iptables ist so konfiguriert dass es für Port 22 offen ist.


    Sobald ich via Putty übers Internet auf den Pi zugreifen will und das Passwort eingeben hab bei <benutzername>@xxxxxx.dyndns.net , rödelt er 1-2 Sek. und meint dann stumpf <Access denied>.


    Ich raffe einfach nicht mehr woran, das noch liegen könnte.


    Habt ihr damit Erfahrung ?


    Gruß


    Timo

  • Ändere den Port (Zugriffsport "von aussen" unbedingt auf einen andere Port (5-stellig ist gut).

    Die Portweiterleitung muss du natürlich auch anpassen...


    IPtables brachst du nicht konfigurieren..


    Du greifst "von aussen" auf den Port 22 der FB zu, welcher vermutlich natürlich gesperrt ist...

  • Ändere den Port (Zugriffsport "von aussen" unbedingt auf einen andere Port (5-stellig ist gut).

    Pardon, aber das ist kompletter Unsinn. Vor allem die Behauptung man solle es auf einen fünfstelligen Port setzen. Alle Ports unter 1024 sind privilegierte Ports und können ausschließlich vom Superuser belegt werden (bzw. es benötigt der entsprechende Prozeß mindestens CAP_NET_BIND_SERVICE. Bei Ports unterhalb von 1024 kann man sich also zumindest sicher sein, daß ein privilegierter Benutzer (vulgo: Admin) den Dienst anbietet und nicht jeder dahergelaufene Benutzer der mal Bock hat sich dazwischenzuschalten. Wenn man dann noch Benutzer hat die darauf trainiert werden Warnungen zu den öffentlichen Schlüsseln zu ignorieren, ist das Desaster vollkommen.


    Generell ist von einem Umbiegen der Standardports in etwa soviel zu halten wie vom Blockieren oder Fallenlassen von ICMP-Paketen (bspw. Ping). Ein Angreifer kann auch beim Fallenlassen von ICMP-Paketen herausbekommen, daß es den Host gibt, spätestens indem der eine Dienst den der Rechner bspw. bereitstellt ganz regulär auf Anfragen antwortet. Wo ist der Sicherheit gedient wenn ich mich als Admin der Möglichkeiten von ICMP beraube - weil ich irgendwann vom Ping of Death auf Windows 95 gehört habe - aber gleichzeitig öffentliche Dienste auf dem Server anbiete? Ähnliches gilt bei SSH, auch wenn sich die Portangabe relativ komfortabel via ~/.ssh/config festlegen läßt.


    Das Stichwort hierbei ist Security Through Obscurity. Verstecken macht nichts sicherer. Es macht es nur zeitaufwendiger für irgendwelche automatisierten Prozesse deinen Host auf Dienste abzuklopfen. Aber ich hab noch nie ein Skript gesehen, welches sich beschwert hätte, weil es eine sehr langweilige Aufgabe erledigen muß.


    Allerdings ist die Idee zumindest einen Test wert, weil vielleicht der Provider Port 22 pauschal sperrt. Dann könnte ein Umbiegen des Ports angezeigt sein, aber bitte auf einen privilegierten Port. 1022 ist übrigens kleiner als 1024 und leicht zu merken ;)


    Am effektivsten ist es insgesamt in der sshd_config einzutragen daß 1. Root sich nicht einloggen darf (dann lieber einen sudoer einloggen lassen) und daß 2. nur Schlüssel und keine Paßworte akzeptiert werden.


    Netfilter kann und sollte man schon konfigurieren, ggf. delegiert man das an eine Lösung wie fail2ban. Diese Software versteht mittlerweile scheinbar auch IP Sets und ist damit technisch auf dem Stand der Zeit. IP Sets sind deutlich flexibler zu handhaben als einzelne Regeln oder Regeln die sich auf Subnetze beziehen. Das war gerade auch früher ein Problem, weil irgendwann Netfilter aufgab und keine neuen Regeln mehr annahm.


    Will man es händisch einrichten bietet sich das Recent-Modul an, welchem man auftragen kann eine Liste mit IPs innerhalb eines bestimmten Zeitintervalls vorzuhalten. Da die Kapazität und Flexibilität dieser Methode begrenzt ist, sollte man das nur als Eintrittspunkt in die Teergrube einsetzen um die Angreifer schön auszubremsen (denn die probieren vor allem massenweise Benutzernamen und Paßworte). Das kann man dann mit einem IP Set kombinieren, welches man ganz bequem per IP-Filter-Regel befüllen und aktualisieren kann. Da man den Einträgen eines IP Sets einen Timeout mitgeben kann, können Sperreinträge automatisch nach einer gewissen Zeit wieder entfernt werden. Man sollte aber vorzugsweise immer wieder den Eintrag im IP Set aktualisieren um hartnäckige Angreifer schön auf der Liste zu halten.


    Kombiniert man das noch mit einer Liste von IP-Blöcken nach Herkunftsland und weiß, daß man bspw. nie aus Bahrain zu seinem Server verbinden wird, kann man ganze Regionen pauschal vom SSH-Zugang ausschließen.


    Persönlich habe ich zwei Teehgruben basierend auf einer Unterschiedlichen Anzahl von Verbindungsversuchen. Hier mal nur für IPv4 (iptables-save-Notation):


    Code
    -A SSH -j SSHCONN
    -4 -A SSH -p tcp -m conntrack --ctstate NEW -m recent --name fastpit --set
    -4 -A SSH -p tcp -m conntrack --ctstate NEW -m recent --name slowpit --set
    -4 -A SSH -p tcp -m conntrack --ctstate NEW -m recent --name fastpit --update --seconds 120 --hitcount 3 -j SET --add-set ssh_dynblock src --exist
    -4 -A SSH -p tcp -m conntrack --ctstate NEW -m recent --name slowpit --update --seconds 600 --hitcount 5 -j SET --add-set ssh_dynblock src --exist
    -4 -A SSH -p tcp -m conntrack --ctstate NEW -m recent --name fastpit --update --seconds 120 --hitcount 3 -j REJECT --reject-with tcp-reset
    -4 -A SSH -p tcp -m conntrack --ctstate NEW -m recent --name slowpit --update --seconds 600 --hitcount 5 -j REJECT --reject-with tcp-reset

    So, da hat man nun also fastpit, welche innerhalb von 120 Sekunden nicht mehr als 3 Verbindungsversuche (nicht zu verwechseln mit Paketen an sich) zuläßt. Sowie slowpit, welche innerhalb von 10 Minuten nicht mehr als 5 Verbidungsversuche zuläßt. Sollte einer der Werte überschritten sein, landet der jeweilige "Angreifer" (oder auch ich selbst) auf der schwarzen Liste. Da ich die Regeln kenne, kann ich selbst natürlich einfach warten bis ich wieder ausgelistet bin und dann nochmal von neuem versuchen. In der Praxis passiert das aber nicht (warum? weiterlesen!).


    So, man sieht vielleicht, daß ich ganz oben erstmal in die Chain SSHCONN springe. Und die sieht so aus.

    Hier haben wir also folgendes:


    1. Eine Regel welche die IP dem Set hinzufügt, sofern die IP schon drin war. Klingt seltsam, ergibt aber zusammen mit Timeouts Sinn, weil so ein Eintrag einer IP quasi aufgefrischt wird. Die darauffolgende Regel läßt Verbindungsversuche von vertrauenswürdigen IPs direkt durch (bei mir läuft ein cron-Job der die IPs basierend auf DynDNS immer aktuell hält).

    2. Pakete bereits eingeloggter Benutzer werden immer durchgelassen. Ob ein Benutzer erfolgreich eingeloggt ist, läßt sich bequem innerhalb von PAM ermitteln und Dank des PAM-Moduls pam_exec.so kann ich ein kleines Script abfeuern welche die Herkunfts-IP dem Set hinzufügt.

    3. Schon weiter oben hat man gesehen, daß jene die in der fastpit bzw. slowpit landen auch in dem Set für dynamische Blockierung landen. Das ist sozusagen nur das Langzeitgedächtnis meiner Teergruben, wiederum mit Timeouts versehen und Dank der Regeln werden die Einträge hartnäckiger Benutzer immer aufgefrischt.

    4. Bereits verbundene Clients werden durchgelassen. Haben wir bereits einen erfolgreichen Verbindungsaufbau gehabt, kann ich mir weitere Regeln sparen.

    5. IPs aus allen Ländern außer einer von mir vorgegebenen Liste (wichtig, falls ihr auch mal VPN benutzt), werden pauschal nicht durchgelassen.

    6. Rücksprung zum Aufrufer.


    Die Methode ist verdammt effektiv und vor allem sehr ressourcenschonend für meine Server.


    Eine Alternativmethode die man einsetzen könnte um allen Quark mit DynDNS komplett zu umgehen wäre, daß man - sofern man ohnehin bspw. einen Virtual Private Server (VPS) hat - einfach einen permanenten Tunnel zu dem aufrecht erhält und sich über diesen Tunnel von dem VPS zurück ins heimische Netz hangelt. Die Methode habe ich im Februar auf meinem Blog erläutert (Englisch): https://blog.assarbad.net/20170223/ssh-reverse-tunnel/ ... ich setze sie aber schon seit vielen Jahren erfolgreich ein. Eigentlich war nur die Tatsache, daß ich eine systemd-Unit brauchte Grund einen Blogbeitrag darüber zu verfassen.


    PS: und ja, ich hab die ipfilter-Regeln tatsächlich alle selber geschrieben und mir auch selber ausgedacht.

    Wenn ihr schnell hilfreiche Antworten wollt, lest bitte diesen Artikel (Fehlerberichte - wie Sie Softwarefehler melden sollten) und beherzigt die darin enthaltenen Ratschläge. Herzlichen Dank!

  • Ach ja eine Bemerkung noch. IP Sets können auch andere IP Sets enthalten. Da ein einzelnes Set nur spezifisch IPv4 oder IPv6 Adressen aufnehmen kann (je nach Typ gibt es auch Sets ohne Adressen, bspw. nur mit Ports oder eben mit anderen Sets) hilft diese Methode. So verstecken sich hinter den Namen bei mir oben eigentlich zwei Sets (eines IPv4 und eines IPv6) die in dem o.g. Set zusammengefaßt sind. Die IP-Set-Erweiterung ist clever genug um zu wissen, daß wenn ich eine Adresse einem Set hinzufügen will welches aus IPv4 und IPv6-Sets besteht, es bitte die IP-Adresse je nach Art ins richtige enthaltene Set schiebt.


    Sehr mächtige Funktion, wie ich finde. Leider nicht sonderlich gut dokumentiert.

    Wenn ihr schnell hilfreiche Antworten wollt, lest bitte diesen Artikel (Fehlerberichte - wie Sie Softwarefehler melden sollten) und beherzigt die darin enthaltenen Ratschläge. Herzlichen Dank!

  • Assarbad,


    sorry, das ist mir heute zu viel Text, ich hoffe Du mögest mir das verzeihen?


    Generell ist von einem Umbiegen der Standardports in etwa soviel zu halten wie vom Blockieren oder Fallenlassen von ICMP-Paketen

    Bis dahin hatte ich gelesen und dazu nur soviel... Zentris schrieb von aussen, d.h. aus dem I-Net auf den Router, der wiederum weiterleitet auf den (richtigen) SSH-Port 22.


    Evtl.. war das aus dem Zusammenhang gerissen, aber wie geschrieben: Morschn is ä neuer Dach... ;)

  • Moin raspi_I,


    eigentlich werden solche Fehler sehr gut in der Logdatei vermerkt.

    Einfach mal sudo journalctl -f in einem Terminal eingeben und dann den Kontaktversuch von aussen probieren.

    Dieses Ergebenis dann hier posten.


    Assarbad Das ist wohl etwas "overdressed" und nicht sehr förderlich...


    Gruss Bernd

    Ich habe KEINE Ahnung und davon GANZ VIEL!!
    Bei einer Lösung freue ich mich über ein ":thumbup:"

    Vielleicht trifft man sich in der RPi-Plauderecke.

    Edited once, last by Bernd666: habe noch ein "a" gespendet ().

  • Boah, Wahnsinn, erst einmal vorab ein großes Dankeschön für die vielen schnellen und so mega detaillierten Antworten !!!


    @DG8BR bzw. Hi Bernd,


    Das Kommando sudo journalctl -f funktioniert nicht. (Befehl nicht gefunden). Nehmen an, nicht standardmässig installiert in der Raspbian Stretch Lite ?


    Inhalt auth.log:


    /Anfang /

    Dec 9 09:04:28 raspi_I sshd[921]: Accepted password for timo from 192.168.178.20 port 54845 ssh2

    Dec 9 09:04:28 raspi_I sshd[921]: pam_unix(sshd:session): session opened for user timo by (uid=0)

    Dec 9 09:04:28 raspi_I systemd-logind[349]: New session c1 of user timo.

    Dec 9 09:04:28 raspi_I systemd: pam_unix(systemd-user:session): session opened for user timo by (uid=0)

    Dec 9 09:05:44 raspi_I sudo: timo : TTY=pts/0 ; PWD=/home/timo/sshcheck ; USER=root ; COMMAND=/usr/sbin/service ssh status

    Dec 9 09:05:44 raspi_I sudo: pam_unix(sudo:session): session opened for user root by timo(uid=0)

    Dec 9 09:05:44 raspi_I sudo: pam_unix(sudo:session): session closed for user root

    Dec 9 09:09:01 raspi_I CRON[1124]: pam_unix(cron:session): session opened for user root by (uid=0)

    Dec 9 09:09:01 raspi_I CRON[1124]: pam_unix(cron:session): session closed for user root

    Dec 9 09:11:48 raspi_I sudo: timo : TTY=pts/0 ; PWD=/var/log ; USER=root ; COMMAND=/bin/nano faillog

    Dec 9 09:11:48 raspi_I sudo: pam_unix(sudo:session): session opened for user root by timo(uid=0)

    Dec 9 09:11:50 raspi_I sudo: pam_unix(sudo:session): session closed for user root

    Dec 9 09:12:17 raspi_I sudo: timo : TTY=pts/0 ; PWD=/var/log ; USER=root ; COMMAND=/bin/nano auth.log

    Dec 9 09:12:17 raspi_I sudo: pam_unix(sudo:session): session opened for user root by timo(uid=0)

    Dec 9 09:13:04 raspi_I sudo: pam_unix(sudo:session): session closed for user root

    Dec 9 09:13:06 raspi_I sudo: timo : TTY=pts/0 ; PWD=/var/log ; USER=root ; COMMAND=/bin/nano auth.log

    Dec 9 09:13:06 raspi_I sudo: pam_unix(sudo:session): session opened for user root by timo(uid=0)

    /Ende/


    Beschreibung: Anmeldung (wie man sieht) aus lokalem Netz, der Versuch extern zuzugreifen ist gar nicht protokolliert ?!?



    Vielen Dank nochmal.


    Gruß

    Timo

    Edited once, last by raspi_I ().

  • Was ich nicht ganz nachvollziehen kann ist folgender Satz.

    Sobald ich via Putty übers Internet auf den Pi zugreifen will und das Passwort eingeben hab bei <benutzername>@xxxxxx.dyndns.net , rödelt er 1-2 Sek. und meint dann stumpf <Access denied>.


    Bei Putty wird der Host xxxxxx.dyndns.net und der SSH-Port in Deinem Fall 54845 eingegeben. Nach dem Klick auf Open wird doch erst nach User und Pass gefragt. :conf: ... oder steht bei Dir <benutzername>@xxxxxx.dyndns.net bei Hostname?

    //Edit: Sorry ein Denkfehler. user@host's password: war gemeint.



    Assarbad Habe es gelesen und gebe Dir Recht. Den Port am RPi zu ändern macht keinen Sinn. Im Router würde ich dennoch einen anderen eintragen, so hält man sich wenigstens "Hobbyhacker" vom Hals.

  • Als Addendum: Nettes Repository mit diversen regelmäßig updated IP Listen

    Vergiss nicht Deine Raspberry regelmäßig mit raspiBackup zu sichern ;)

    Darum gebe ich keinen Support per PN und auch nicht auf der Pinwand !

    "Really, I'm not out to destroy Microsoft. That will just be a completely unintentional side effect." Linus Benedict Torvalds, 28.9.2003


  • Pardon, aber das ist kompletter Unsinn. Vor allem die Behauptung man solle es auf einen fünfstelligen Port setzen. Alle Ports unter 1024 sind privilegierte Ports und können ausschließlich vom Superuser belegt werden (bzw. es benötigt der entsprechende Prozeß mindestens CAP_NET_BIND_SERVICE. Bei Ports unterhalb von 1024 kann man sich also zumindest sicher sein, daß ein privilegierter Benutzer (vulgo: Admin) den Dienst anbietet und nicht jeder dahergelaufene Benutzer der mal Bock hat sich dazwischenzuschalten.

    Den Rest des Romans schenke ich mir mal...


    Ich habe angeregt, den externen Port des ssh-Zugangs auf einen Port >9999 zu setzen:

    Warum?

    Üblicherweise werden die Ports <1024 in Internet schon fast routinemäßig gescannt. Der Honeypot-Thread von meigrafd zeigt ja, dass da sehr schnell "Klopfer" vor der Tür stehen...

    Ports mit höheren Werten werden zwar ebenfalls untersucht, aber wesentlich seltener, weil es aufwendiger ist und die offenen Ports <1024 ggf. schnellen Erfolg versprechen (Eben WEIL nicht der Anwender da keine Gedanken gemacht hat).


    Die Aussage unter https://de.wikipedia.org/wiki/…er_standardisierten_Ports

    Quote

    Auf Unix-artigen Betriebssystemen darf nur das Root-Konto Dienste betreiben, die auf Ports unter 1024 liegen. Hier, im Bereich der sogenannten System Ports oder auch well-known ports, ist die höchste Konzentration an offiziellen und bekannten Ports zu finden.

    halte ich für fragwürdig, zumindest was das Betreiben betrifft, das Einrichten geht sicherlich nur als root.

    Ports wie z.B. 80, oder 443 werden üblicherweise durch den Webserveruser eingerichtet und betrieben..


    Aus dem ursprünglichen TO-Post habe ich geschlussfolgert, dass der TO sich als USER ("pi" ?) und nicht als "root" anmelden wollte, somit ist der Zugriff zunächst legitim.

    Was aber schiefgehen kann ist, dass die FB diesen Port "an sich" für den Zugriff von außen sperrt und damit die Portweiterleitung "an sich" nicht greift (Kenne allerdings die FB da nicht weiter, meine Router ignorieren solche Zugriffe grundsätzlich...


    Somit bleibt nur, den ssh-Zugriff von aussen auf einen anderen Port zu setzen...

  • hyle.


    Was ich damit sagen wollte:

    - Zugriff über Putty auf die Domain des Pi ist über das Internet erfolgt:






    Kommunikation scheint also stattzufinden, aber er verweigert das Passwort des Benutzers (Im internen Heimnetz funktioniert es tadellos)..

  • Assarbad:


    Vielen Dank für die ausführlichen Informationen. Ich bin momentan Newbie, inbs. was den Punkt Sicherheit anbelangt. Mir ist klar, dass es Müll ist Standardport zu verwenden und freizugeben. Trage dem momentan mit einem irrsinnig langen Passwort Rechnung (Was mich bei den vielen Logins /sudo zum Wahnsinn treibt ;-) )


    I'm tryring to keep it simple, denn ich bin meiner Meinung nach noch nicht fit genug für komplexere iptables/fail2ban-Einstellungen. Habe auch null weiterführende Literatur.

  • Die Portweiterleitung ist richtig eingerichtet, denke ich. Ansonsten könntest du dich überhaupt nicht mit dem Pi von außen verbinden. Es wird an einer lokalen Einstellung liegen. Neben der sshd_config wäre auch interessant, was der SSH-Daemon ausgibt:


    sudo journalctl -u ssh


    Das Kommando sollte auf deinem Pi existieren, auch beim Lite-Image von Raspbian, denn diese Kombination habe ich hier auch so auf einem Pi 3 installiert.


  • Sind beide nur mit Standardeinstellungen:


    ssh_config


    sshd_config


  • - Zugriff über Putty auf die Domain des Pi ist über das Internet erfolgt:

    Von welchem Internetanschluss greifst Du auf deinen PI zu?


    Hast Du mit deiner FB-cable einen DS- oder einen nativen IPv4-Internetanschluss? Bei welchem Provider hast Du deinen Internetanschluss?

    The most popular websites without IPv6 in Germany.