SFTP mit Key-Authentication auf (gehosteten) Linux-Servern für Web-Entwickler mit unterschiedlichen Privilegien – I

Da ich immer mal wieder SSH- und SFTP-Verbindungen für gehostete LAMP-Test- und LAMP-Produktiv-Server unter Linux (genauer: Opensuse) konfigurieren muss, stelle ich in einer Artikelserie mal ein paar Hinweise zu den durchzuführenden Überlegungen und administrativen Schritten zusammen.

Ich setze im nachfolgend beschriebenen Fall nur das interne SSH-Subsystem für SFTP und Dateitransfers auf den Test-/Produktiv-Server ein. Bzgl. eventuell vorzusehender unterschiedlicher Zugriffsrechte der (S)FTP User genügt aus meiner Sicht die Diskussion eines Beispiels mit 2 User-Gruppen und zwei unterschiedlichen (Domain-) Verzeichnissen auf dem Server.

Ich gehe im Folgenden davon aus, dass der Leser bereits über etwas Erfahrung mit der Einrichtung von SSH auf einem Remote-System besitzt. Wenn nicht: Siehe
Strato-V-Server mit Opensuse 12.3 – IV – SSH Key Authentication
und vorhergehende Artikel. Im vorliegenden, ersten Artikel der aktuellen Serie behandle ich grundlegende SSH-Einstellungen nur relativ kurz und diskutiere sie hauptsächlich unter Sicherheitsaspekten. Ein zweiter Artikel befasst sich dann mit der konkreten User-Einrichtung für die SFTP-Nutzung.

Abgrenzung SFTP-Uploads von SVN-Updates über SSH

Wir lassen im diskutierten Kontext die Möglichkeiten von SVN (in Kombination mit SSH) für das systematische Füllen von Domain-Verzeichnissen des (Web-) Test-Servers außer acht – obwohl viele Entwickler dies aus Bequemlichkeit nutzen.

Nach meiner Ansicht hat die Code-Versionsverwaltung in Entwicklungsphasen logisch nur wenig mit dem gezielten Upload konsolidierter Dateien einer bestimmten SW-Test- oder -Produktiv-Version in entsprechende Domainen eines Web-Test- oder -Produktiv-Servers zu tun. Letzteres – also der Upload – entspricht eher Export-Vorgängen (z.B. unter Eclipse) oder eben gezielten FTP-Transfers. Unter diesen Prämissen wie auch unter Sicherheitsaspekten hat SVN auf einem exponierten Test- oder Produktivsystem eigentlich wenig verloren. SVN ist vielmehr Teil der Service-Landschaft der Entwicklungsumgebung im lokalen Netz und dient dort der laufenden Protokollierung von Versionsständen einzelner SW-Files sowie deren Konsolidierung.

Elementare Ziele, Anforderungen und Voraussetzungen

Gehosteter Server
Der Server habe die Adresse “serv@myhoster.net” und sei gehostet. Der reguläre SSH-Zugang zu diesem Server für Verwaltungszwecke erfolge zunächst über einen (unpriviligierten) User “usu” über den (high) Port “xxxxx”. Über den “usu”-Account und die Shell logt man sich dann bei Bedarf als “root” ein.

Authentifizierung über Private/Public SSH-Keys
Ein sicherheitsrelevanter Aspekt ist im Falle gehosteter Server die Authentifizierung der Entwickler mittels

  • eines privaten SSH-Keys auf dem Client
  • sowie dessen Gegenstück, nämlich eines auf dem Server hinterlegten Public Keys,

anstelle von User IDs und Passwörtern. Ich gehe im ersten Beitrag auf die wichtigsten zugehörigen Anweisungen in der SSHD Konfigurationsdatei ein. Durch Key-Authentication lassen sich Brute Force Angriffe auf den SSH-Zugang eindämmen; als Admin sollte man aber nicht übersehen, dass durch ein solches Verfahren auch die Anforderungen an die sichere Verwahrung der Schlüssel auf den Clients steigen.

Passwortschutz des private Keys auf dem Client – ?
Eine “Private Key”-Datei auf einem Client-System stellt eine potentielle Gefahrenquelle dar:

  • Mobile Clients können gestohlen werden.
  • n

  • Desktops wie mobile SSH/SFTP-Clients können gehackt werden.

Ein Passwortschutz des privaten Keys ist deshalb eine Mindestanforderung an die Sicherheit – wenngleich auch das nicht gegen implantierte Key-Logger schützt. Eine interessante Frage ist deshalb:

Was gilt im Zshg. mit Key-Passwortschutz eigentlich für gängige SFTP-Clients?

Welcher SFTP-Client unterstützt den Umgang mit Private Keys, wenn diese im Sinne einer durchgehenden Sicherheit auf den Client-Systemen passwort-geschützt hinterlegt werden sollen? Ich gehe in einem der nachfolgenden Artikel deshalb kurz auf diese Frage ein.

Kein SSH-Shell-Zugang
Die User – hier Entwickler – sollen das SSH-basierte SFTP nur für File-Transfers nutzen; sie sollen auf dem Server jedoch keinen Shell-Zugang über SSH erhalten. Administrative Aufgaben auf Test- oder Produktiv-Servern remote durchzuführen, bleibt in unserem Szenario ausschließlich Server-Administratoren vorbehalten.

Verzeichnisse, Entwicklergruppen und Rechte
Während die Einrichtung des SFTP-Servers für eine Key-Authentifizierung nur wenig von Vorgehensweisen abweichen dürfte, die bereits an anderer Stelle im Internet beschrieben sind, ist in unserem Beispiel ein zusätzlicher Punkt folgender:

In Web-Entwicklungsprojekten ist es sinnvoll, definierte Gruppenrechte und manchmal auch User-Rechte auf bestimmten SFTP-Verzeichnissen des Servers – die dort in der Regel Web-Domain-Verzeichnisse umfassen – zu erzwingen. Warum?

  • Einerseits will man die User (Entwickler) womöglich in Log-Dateien unterscheiden können. Man wird Ihnen (genauer: ihren UIDs) deshalb in jedem Fall unterschiedliche Authentifizierungs-Keys zuordnen. Ferner sollen die Entwickler ggf. aber auch gruppenübergreifend kollaborieren. Deshalb braucht man abgestimmte Lese- und Schreib-Rechte auf Verzeichnissen für eine (oder mehrere) definierte Gruppe(n). Für die Darstellung besonderer Privilegien können auch user-bezogene Rechte erforderlich werden. Das Schreibrecht wird man auf einem exponierten Web-Server in jedem Fall so gut wie nie “others” zuordnen.
  • Zudem ist zu gewährleisten, dass der Webserverprozess selbst transferierte Directories und Files lesen und im Falle der Bereitstellung von dynamisch geschriebenen Download-Dateien auch beschreiben kann. Der User, unter dem der Webserver-Prozess läuft, muss auch dann wieder Teil einer Gruppe werden, wenn man “others” keine Schreibrechte zuordnen will.
  • Es ist durchaus normal, dass unterschiedliche Privilegien des Zugriffs auf Verzeichnisse in ein und derselben Verzeichnis-Hierarchie für die Mitglieder unterschiedlicher Entwicklergruppen gefordert werden. Der Zugang zu bestimmten Verzeichnissen und Subverzeichnissen soll in unserem Beispiel per SFTP Chroot und durch das Setzen von Zugriffsrechten auf bestimmte Verzeichnisse limitiert werden. Die Entwickler sollen in unserem Beispiel in 2 Gruppen mit unterschiedlichen Zugriffsrechten auf die Verzeichnishierarchie unterteilt werden.

Wir lassen ferner Zugriffe nur auf Web-Domain-verzeichnisse zu; wir erlauben den Entwicklern keinen Zugriff auf private Home-Verzeichnisse.

Zwei Entwickler-Gruppen mit unterschiedlichen Privilegien
Wir diskutieren in unserem Beispiel den abgestuften Zugriff zweier unterschiedlich privilegierter Entwicklergruppen auf Verzeichnisse unterhalb eines Chroot-Jails “/srv/www/htdocs/webs/project”.

/srv/www/htdocs/webs/project
|
— test
|
— adm
|
— rc

Die Subverzeichnisse entsprechen z.B. verschiedenen Web-Domainen oder Entwicklungsprojekten mit jeweils weiteren Sub-Sub-Verzeichnissen. Da unterschiedliche Berechtigungen für die Domain-Verzeichnisse gegeben sein sollen, werden im Beispiel zwei
Usergruppen devgrp1 und devgrp2 eingerichtet.

Zusätzlich wird der Zugriff der Gruppe “devgrp2” auf Inhalte eines weiteren Chroot-Verzeichnis – hier “test” – eingeschränkt. Die Mitglieder der “devgrp1” dürfen dagegen auf alle definierten Domain-Verzeichnisse zugreifen. Sie sind deshalb zugleich sekundäre Mitglieder der “devgrp2”.

Als Beispiel-User wählen wir hier die User “alpha” (Mitglied von “devgrp1” und “devgrp2”) und “beta” (Mitglied von “devgrp2”). Andere Berechtigungsszenarien lassen sich später aus diesem Beispiel zwanglos ableiten.

  • Mitglieder devgrp1: alpha (Zugriff auf alle Verzeichnisse)
  • Mitglieder devgrp2: beta, alpha (Zugriff nur auf Inhalte von “test”)

Grundlegende Konfiguration und Sicherheitsaspekte der SSH-Einrichtung

Wie man einen Opensuse-Server bei einem Hoster wie Strato grundsätzlich für einen SSH-Zugang mit verschobenem Port und Key-Authentifizierung konfigurieren kann, habe ich bereits in früheren Artikeln in diesem Blog besprochen. Siehe etwa:
Strato-V-Server mit Opensuse 12.3 – IV – SSH Key Authentication
und vorhergehende Artikel.

Ich gehe in diesem Artikel entsprechend davon aus, dass es bereits einen elementar eingerichteten SSH-Service gibt und diskutiere nur einige wichtige Optionen der Konfigurationsdatei “/etc/ssh/sshd_config” des einzurichtenden SSHD-Daemons (s.u.).

Ein paar Hinweise und Warnungen:

Je nachdem, was man an Hosting-Paket (Virtual Server etc.) geordert hat, richtet der Provider eine elementares Linux mit SSH-Zugang ein – meistens ausschließlich für den User root. In der Regel wird man das System in einem ersten Schritt upgraden/updaten und danach auch die SSH-Konfiguration remote und schrittweise abändern. Dabei ist Vorsicht angebracht! Man will sich bei Experimenten mit der SSH-Konfiguration ja schließlich nicht selbst vom Systemzugang ausschließen. Bitte beachten Sie die diesbzgl. Hinweise in den oben genannten Artikeln. Unbedingt sollte man sich beim Provider nach Notfall-Maßnahmen im Falle eines nicht mehr möglichen SSH-Zugangs erkundigen. Meist ist das Booten eines Notfall-Systems mit anschließendem Platten- und Dateizugriff möglich …. Die Notfall-Maßnahmen sollte man auch mal ausprobieren …

Im Zshg. mit SSH- und System-Startup-Modifikationen ist dafür zu sorgen bzw. zu prüfen, dass der SSHD-Daemon bei jedem (automatischen) Systemstart aktiviert wird. Gerade bei gehosteten Servern ist dies ein kritischer Punkt. Provider fahren u.U. die gehosteten Server ohne Rückfrage automatisch rauf und runter, wenn Wartungsmaßnahmen dies erfordern. Nach einem solchen Reboot muss natürlich der SSH-Service auch wieder verfügbar sein.

Jemand der SSH selbst auf einem gehosteten Server konfiguriert, sollte sich deshalb auf Opensuse-, Red Hat- und künftig wohl auch Debian-Systemen mit den entsprechenden Optionen des “systemctl”-Kommandos von “systemd” vertraut machen und überprüfen, dass der SSH(D)-Service für den automatischen Start beim Booten aktiviert ist. Unter Opensuse führt

systemctl enable sshd.service

zur Aktivierung. Den aktuellen Service-Zustand – inkl. Aktvierung – prüft man mit:

mylinux:~ # systemctl status sshd.service
sshd.service – OpenSSH Daemon
Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled)
Active: active (running) since Sat 2015-08-08 09:16:50 CEST; 3h 9min ago
Process: 1615 ExecStartPre=/usr/sbin/sshd-gen-keys-start (code=exited, status=0/
SUCCESS)
Main PID: 1650 (sshd)
CGroup: /system.slice/sshd.service
└─1650 /usr/sbin/sshd -D
 
Aug 08 09:16:50 mylinux sshd-gen-keys-start[1615]: Checking for missing server keys in /etc/ssh
Aug 08 09:16:50 mylinux sshd[1650]: Server listening on 0.0.0.0 port xxxxx.
Aug 08 09:16:50 mylinux sshd[1650]: Server listening on :: port xxxxx.

Das korrekte Reboot-Verhalten des gehosteten Servers ist nach Systemeingriffen natürlich nicht nur für SSH/SFTP sondern auch andere Serverdienste zu testen.

Ferner gilt:

Bevor man bestimmte User definitiv vom SSH-Zugang ausschließt, sollte man immer die Zugangsmöglichkeit für einen oder mehrere verbleibende User explizit testen. Mindestens ein verbleibender User sollte immer vorhanden sein.

Ähnliches gilt für die Umstellung auf Key Authentication:

Bevor man eine passwort-basierte Authentisierung für alle User abstellt, sollte man zunächst ausschließlich mit userspezifischen Festlegungen arbeiten und für einzelne User die Funktionstüchtigkeit der Key-Authentifizierung testen. Zur Einrichtung userspezifischer SSHD-Konfiguration dienen die “Match”-Anweisung und zugehörige Blöcke am Ende (!) der SSHD-Konfigurationsdatei. Man lese hierzu unbedingt die ssh-man-Seiten.

Auch der nachfolgende Artikel

SFTP mit Key-Authentication auf (gehosteten) Linux-Servern für Web-Entwickler mit unterschiedlichen Privilegien – II

zeigt beispielhaft, wie man userspezifische Anweisungen anlegt und wie diese aussehen können.

SSH-Zugang für root?
Der direkte SSH-Zugang für root sollte auf einem exponierten System i.d.R. nicht zugelassen werden. Er ist auch überhaupt nicht erforderlich. Erlaubt werden soll und muss der SSH-Zugang im Anfangsstadium dagegen für einen bereits erwähnten, unpriviligierten User “usu”.

Ein solcher unpriviligierter User muss auf dem gehosteten Server erstmal eingerichtet werden. Meist existiert auf gehosteten Servern anfänglich nur der User root. Bevor man den SSH-Zugang für root sperrt, muss der Zugang inkl. Shell-Nutzung für den neuen unpriviligierten User explizit getestet werden. Die Zugangsdaten des unpriviligierten Users sind vom Admin geheimzuhalten. Dieser Account bleibt sein Weg ins System – über den “usu”-Account erfolgt dann indirekt über “su -” der Login als root.

Für den User “usu” sei auf unserem Server bereits ein Public/Private-Key-Paar eingerichtet. Siehe hierzu den oben erwähnten Artikel. Wie man das für andere Accounts macht, zeigt beispielhaft auch der zweite Artikel dieser Serie.

Begrenzung des SSH-Zugangs auf bestimmte IP-Adressen?
Eine spezielle Sperre des Zugangs für allgemeine Host-IP-Adressen bzw. eine Zugangserlaubnis für definierte IP-Adressen gestalte ich normalerweise über eine Firewall und nicht über die SSH-Konfiguration. Die Firewall erlaubt dann für vordefinierte IPs den Zugang zu einem definierten High Port xxxxx für SSH und zu einem definierten Port für HTTPS.

Es sei an dieser Stelle aber ausdrücklich auch darauf hingewiesen, dass die weiter unten benutzte Anweisung

AllowUsers uid

Zusätze der Form

AllowUsers uid@ip.add.re.ss

erlaubt. Gerade bei wenigen SSH/SFTP-Usern, die immer von Clients mit fixer IP-Adresse aus zugreifen, ist das eine gute Möglichkeit, die Nutzung des SSH-Services weiter einzugrenzen.

An dieser Stelle sei auch angemerkt, dass man auf Systemen mit mehreren Netzwerk-Interfaces eingrenzen kann, auf welchem Interface der SSHD angeboten werden soll. Dies geht über die IP-Adresse, die dem Interface zugeordnet ist und der Direktive “ListenAddress”. Für mehr Informationen siehe etwa:
http://www.thegeekstuff.com/2011/
05/openssh-options/

Portverschiebung – Obfuscation
Der Nutzen einer Zuordnung des SSH-Services zu einem selbst definierten Port (hoher Portnummer) wird unterschiedlich diskutiert. Ich persönlich ändere den SSH-Port regelmäßig ab, da zumindest meine Erfahrung zeigt, dass die Anzahl bestimmter Angriffsversuche von Skript-Kiddies danach zurückgeht. Nachfolgend steht “xxxxx” für eine 5-stellige High-Port-Nummer.

Ausschnitte aus der SSHD-Konfigurationsdatei “/etc/ssh/sshd_config”

Nachfolgend ein paar Anweisungen aus einer finalen Konfigurationsdatei für den SSHD als Grundlage von SFTP:

Port xxxxx 
# z.B. Port 64311

AllowUsers usu 
PermitRootLogin no
....
....
RSAAuthentication yes
PubkeyAuthentication yes

# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
# but this is overridden so installations will only check .ssh/authorized_keys
AuthorizedKeysFile   .ssh/authorized_keys

# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication no
#PermitEmptyPasswords no

# Change to no to disable s/key passwords
ChallengeResponseAuthentication no

# Set this to 'yes' to enable PAM authentication, account processing, 
# and session processing. If this is enabled, PAM authentication will 
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication.  ....
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
UsePAM yes

AllowAgentForwarding no
AllowTcpForwarding no
GatewayPorts no
X11Forwarding no
#X11DisplayOffset 10
#X11UseLocalhost yes
#PrintMotd yes
#PrintLastLog yes
#TCPKeepAlive yes
#UseLogin no
UsePrivilegeSeparation sandbox          # Default for new installations.

# override default of no subsystems
#Subsystem      sftp    /usr/lib/ssh/sftp-server -u 0007
Subsystem       sftp    internal-sftp

# This enables accepting locale enviroment variables LC_* LANG, see sshd_config(5).
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL

MaxSessions 50
MaxAuthTries 20
MaxStartups 20

....
.....

Hinweis zur SFTP-Aktivierung:
Zu beachten ist die Aktivierung des internen SSH SFTP-Subsystems über

Subsystem    sftp    internal-sftp

Das ist zunächst die einzige Stelle, an der SFTP hier überhaupt ins Spiel kommt! Und noch ein Hinweis für für erfahrene Admins: die “-u” Option von internal-sftp wird hier nicht angewendet. Wir kommen darauf im 2-ten Artikel dieser Serie zurück.

Wichtiger Hinweis zum schrittweisen Vorgehen:
Bitte beachten Sie, dass Sie eine solche finale Konfiguration, die den SSH-Port verschiebt sowie root-Zugang und einen passwort-basierten Zugang grundsätzlich ausschließt, im Sinne der obigen Warnungen nur schrittweise etablieren sollten. Sehen Sie hierzu die oben erwähnten anderen Artikel dieses Blogs.

Kommentierung einiger sicherheitsrelevanter Anweisungen in der SSHD-Konfiguration

So absurd sich das anhören mag: Ein grundsätzliches Problem im Zusammenhang mit SFTP ist gerade, dass wir auf dem entsprechenden Server SSH einrichten müssen.

Der Grund für diese Aussage ist: SSH in den Händen gewiefter und böswilliger User stellt ein enormes potentielles Sicherheitsproblem dar. Siehe z.B.:
http://
www.informit.com/articles/article.aspx?p=602977

https://threatpost.com/encrypted-tunnels-enable-users-circumvent-security-controls-060109/72742

Eines der größten Probleme ist, dass User mit Shellzugang SSH dazu benutzen können, um sog. “Reverse Tunnels” zu privaten Systemen durch Firewalls hindurch zu etablieren, und in diesem Zusammenhang sogar eigene Port-Forwarding Tools einsetzen. Die aus meiner Sicht wirksamen Sicherheitsmaßnahmen gegen dieses Gefährdungspotential sind in diesem Zusammenhang:

  1. den Zugang zu SSH auf wenige User einzugrenzen
  2. den Usern, die SSH lediglich als Basis von SFTP oder als Basis von geplanten, verschlüsselten Tunneln zu Applikationen einsetzen dürfen, den Shellzugang zu entziehen.
  3. Massive Strafandrohungen bei Verletzung von Policies, wenn Administratoren Shell-Zugangsrechte erteilt werden müssen.

Welche Einstellungen in der obigen Datei sshd_config betreffen die Sicherheit?

Wir erkennen zunächst das Sperren des root-Users für SSH über die Anweisung “AllowUsers”. Ein irgendwie geglückter SSH Crack beinhaltet dann zumindest nicht unmittelbar das Risiko einer Betätigung mit Root-Rechten.

Ferner sehen wir die Festlegung eines besonderen Ports “xxxxx” für den SSH-Service. Dieser TCP-Port muss natürlich in der Firewall geöffnet werden. Die Verschiebung des SSH-Services vom Standardport hält gewiefte Angreifer, die ausführliche Portscans unternehmen, deshalb nicht lange ab.

Password-Authentifizierung ist trotz PAM im Sinne der Kommentare im Konfigurationsfile abgeschaltet. Wir lassen PAM hier an, um auf PAM-Ebene noch weitere Möglichkeiten zur User-Einschränkung bzw. User-Überwachung zu bekommen. Wer dem nicht traut, kann die Nutzung von PAM aber auch abschalten.

Die Zeilen

RSAAuthentication yes
PubkeyAuthentication yes

sorgen dagegen für die von uns gewünschte Authentifizierung mit asymmetrischen RSA-Schlüsseln.

Unterbinden von Port Forwarding und Gateways für Tunnel
Da wir für SFTP kein TCP-Forwarding über SSH benötigen, schalten wir es aus Sicherheitsgründen ab. Die Nutzung unseres Servers als SSH-Gateway ist aus Sicherheitsgründen völlig unerwünscht. Wir schalten deshalb auch den Parameter GatewayPorts ab. X11 sollen unsere lieben SFTP-User natürlich auch nicht nutzen.

Das Einrichten und Nutzen von problematischen Reverse Tunnels über unseren Server ist damit künftig für unsere Entwickler schon nicht mehr so ohne weiteres möglich. Wir müssen weiter unten dennoch den Shell-Zugang für die definierten SFTP-User “alpha” und “beta” sperren, denn, wie die SSH-man-page so schön ausführt, gilt

Note that disabling TCP forwarding does not improve
security unless users are also denied shell access, as they can
always install their own forwarders.

U.a. netcat, portfwd und socat sind entsprechende Tools. See
https://www.digi77.com/the-art-of-port-forwarding-on-linux/
http://29a.ch/2009/5/10/forwarding-ports-using-netcat
Aber es geht u.U. auch einfacher:
http://clinging-to-reality.blogspot.com.br/2014/06/reverse-ssh-tunnel-if.html

Ein grundsätzlich wichtiger Punkt ist in diesem Kontext immer auch, dass ein umsichtiger Admin dafür sorgt, dass der sshd-Dämon auf dem Server nicht von jedermann gestartet werden kann:

chmod 754 /usr/sbin/sshd

Zur Sicherheit sollte man auch Compiler deaktivieren,
um das Kompilieren eigener Module aus eigenen Source-Quellen zu unterbinden.

Siehe zu einer Diskussion von Gefahren durch SSH und im Besonderen durch SSH Reverse Tunnels etwa:
http://www.techexams.net/forums/off-topic/67117-circumventing-network-security-via-ssh-tunneling.html

Einige Aspekte der Sicherheit werden im Zusammenhang mit verketteten Tunneln auch in folgendem Artikel angesprochen:
https://linux-blog.anracom.com/2013/11/22/ssh-getunnelter-datenbankzugang-fur-gehostete-lamp-server-i/

Sicherheitsanforderungen im Umgang mit privaten Schlüsseln

An dieser Stelle ist der dringende Hinweis angebracht, dass das sichere Verwahren von privaten Schlüsseln auf SSH/SFTP-Clients weiterer Schutzmaßnahmen bedarf. Hinsichtlich der Sicherheit ist immer die gesamte Kette der involvierten Systeme zu betrachten! Ein SSH-Auth-Key auf einem Windows-System in einem privaten oder öffentlichen Netzwerkumfeld ist ohne weitere Schutzmaßnahmen ggf. gefährlicher als eine Authentifizierung mit User IDs und einem generierten Passwort! Ferner:
Es gibt Leute,

  • die die Verwendung ein und desselben Key-Paars für verschiedene Server
  • und die dauerhafte Verwahrung von Keys auf einem System ohne weitere Verschlüsselungskomponenten wie etwa für die Dateisysteme, auf denen die Schlüssel gelagert werden,

für potentiell gefährlich halten. Gerade der zweite Punkt ist im Zusammenhang mit einem oben bereits diskutierten Diebstahl (z.B. eines Laptops) unbedingt zu unterstreichen. Ich meine aber, dass der generellen Absicherung der Client-Systeme im regulären Betriebszustand eine ebenso große Bedeutung zukommt. Auf einem Client-System, das mit Key Loggern und Trojanern kompromittiert wurde, nutzt der Einsatz einer schlüsselbasierten Authentisierung gar nichts.

Es versteht sich aus meiner Sicht von selbst, dass der private Schlüssel zusätzlich durch ein Passwort geschützt sein sollte. Man tut deshalb gut daran, sich nach FTP-Clients umzusehen, die Key-Authentifizierung mittels passwortgeschützten Private Keys unterstützen.

Genug für heute. Der nächste Artikel

SFTP mit Key-Authentication auf (gehosteten) Linux-Servern für Web-Entwickler mit unterschiedlichen Privilegien – II

befasst sich dann mit der konkreten Einrichtung unserer SFTP-User.

Allgemeine Links

http://www.unixlore.net/articles/five-minutes-to-even-more-secure-ssh.html

http://www.thegeekstuff.com/2011/05/openssh-options/

Hosted Strato server – backups and chained firewall tunneling via SSH and shell

I administer several Linux web servers for partner and customer companies. Most of these servers are V-servers hosted at the German Telekom daughter Strato.

[I have described some reasonable security measures for a Strato server with Opensuse in some articles in this blog. See e.g.:
Strato-V-Server mit Opensuse 12.3 – IV – SSH Key Authentication
Strato-V-Server mit Opensuse 12.3 – III – Stop SSH Root Login
and previous articles referenced there.]

When you work with a hosted server, of course, you want to perform periodic backups. If you – for whatever reasons – do not want to pay for the backup facilities Strato offers, a backup requires that you transfer data from the remote server into your own company network through (encrypted) SSH tunnels. Depending on your specific situation you may wish to create a complete backup or a backup of selected directories on the server. During the backup you want to preserve user-rights and mode settings.

In addition to the topic of creating tunnels across firewalls, the question arises what Linux tool might be convenient to perform the backup task if you work with a shell based connection only. Therefore, I shall briefly discuss what I normally do to perform a manually controlled backup from a hosted Strato server. You can combine the methods described of course with some scripting. The described firewall tunneling by SSH is independent of a specific provider.

Tunneling firewalls with SSH

We presume that our company network has a DMZ with two firewalls – a perimeter firewall “PFW” protecting the DMZ and its hosts against the Internet and one or several inner firewalls “IFW(s)” separating the DMZ from inner network segments. Creating firewall tunnels on the outer and/or inner side of the DMZ is always a critical issue.

Our own backup server system for customer data – let us call it “bup” – is e.g. located in an inner segment of our network. The perimeter firewall “PFW” to the Internet resides on a router and can be configured to forward external WAN ports to ports of special hosts inside the DMZ. Servers inside an inner network segment are allowed to build up SSH connections to hosts in the DMZ across their “IFW(s)”; however the servers in the DMZ are not allowed to initiate SSH connections to the servers in the inner segments. For security reasons we poll data from the servers in the DMZ; we do not forward or push from the DMZ to inner segments. For our scenaio we assume that there is only one inner segment and that we only have to deal with a single “IFW”.

I personally prefer a 2-step process to get the data from the hosted server to the backup destination server “bup”:

  • Step 1: I open a reverse SSH tunnel from a special host “intmid” in our DMZ to the Strato server on the Internet and transfer the data from the Strato server to “intmid”. There, I first of all scan the backup files for viruses and malware.
  • Step 2: Afterwards I stop the reverse tunnel and disallow any incoming connections to “intmid”. I then open a ssh reverse tunnel from my destination server “bup” to “intmid” across the IFW, transfer the files to “bup” and encapsulate them there in an encrypted container.

Some readers may think a 2 step procedure may be exaggerated. If you prefer direct connections from the hosted Strato server to “bup” inside your network you may

  • either use a chain of two reverse SSH tunnels (one tunnel per firewall)
  • or a combination of port forwarding on the “PFW” with
    a reverse tunnel across the “IFW”

Both solutions provide a complete connection from the Strato server to “bup” passing both firewalls of your DMZ. Below I describe both methods briefly.

In both of the following methods we need a reverse SSH tunnel from the backup destination server “bup” (inner segment) to the DMZ host “intmid”. I.e., we export a SSH port of server “bup” temporarily to the host “intmid” in the DMZ. This you may e.g. achieve by entering the command

ssh -R 19999:localhost:22 ssh_user_on_intmid@intmid

at your prompt on host “bup”. The “-R” option triggers the creation of a “reverse” tunnel. Port 19999 is assumed to be unused on “intmid”; port 22 is your local port on “bup” for the SSH daemon sshd. “ssh_user_on_intmid” represents a user for SSH connections on “intmid” with sufficient privileges.

Note: If you just want to build the tunnel in the background without using a terminal or executing remote commands you may use the following combination of options for SSH (instead of a plain “-R”) : ssh -nNTfR …...
Please see the man pages of ssh. These options may be especially helpful when using scripts. So, a more general form of the command could be

ssh -p<sshd port server> -nNTfR <forwarded port server>:localhost:<sshd port local> <username>@<ip server>

Note 1: If and when you really work with background SSH tunnels: Take care not to forget to stop the processes for the background tunnels at the end of your backup operation! In scripts this requires some “pid” determination operations for the running ssh processes.

Note 2: Depending on your sshd configuration you may need to have root rights to build the tunnel.

You can test your reverse tunnel through the inner firewall “IFW” by entering

ssh -p 19999 userid_on_bup@localhost

at the prompt of the “intmid” host. You will of course be asked for the password of a valid user “userid_on_bup” on server “bup” and should then get a prompt on “bup”.

Method 1: Chaining two reverse tunnels

The hosted Strato server allows for a ssh connection on a specific port as this is your only way to work on it. You can use this SSH-connection to build up a reverse tunnel from your DMZ host “intmid” to the Strato server. I.e., the SSH port of your DMZ host shall be exported e.g. as port 19999 on the hosted Strato server. By issuing the following command on “intmid” we tunnel the perimeter firewall “PFW”:

ssh -R 19999:localhost:19999 strato_user@ip_of_your_Strato-server -p 61111

Note: Here we have assumed that the Strato-Server listens on port 61111 as its configured SSH port. (Normally, I change the standard port 22 to a high port number. See:
Strato-V-Server mit Opensuse 12.3 – II – Installation / SSH-Port ändern)

You will of course have to give the password for your “strato_user” on the hosted Strato server before entering the shell there.

Why did we use port 19999 on the DMZ host “intmid”? Because we want to chain the two tunnels – the one from “bup” to “intmid” in the DMZ across firewall “IFW” and the one from “intmid” to our Strato server on the Internet across firewall “PFW” to get a complete encrypted connection from the Strato server to “bup”. Both tunnels “meet” at port 19999 on host “intmid”.

Now, at the prompt of the Strato server you can test the combined (reverse) SSH tunnels by entering

ssh -p 19999 userid_on_bup@localhost

Note: Do not get confused by “localhost” in the command above. You must provide the password for user “userid_on_bup” on the server “bup” (!) inside our inner network segment. Our connected tunnels end up there!

You then should get a prompt for user “user_id_on_bup” on our server “bup”. Ok, we now can successfully tunnel two firewalls at the same time by making use of 2 chained reverse SSH tunnels!

Method 2: Port forwarding on the perimeter firewall

Port forwarding on the perimeter firewall could be an alternative to chaining two tunnels. Having build our obligatory reverse tunnel from “bup” to “intmid” we could in addition change the behavior of our PFW – provided of course that it is configurable. In my case I can establish port forwarding for incoming connections on an some external (WAN) port from a defined IP address on the Internet to a definable port of any host at the other (DMZ) side of the perimeter firewall. E.g I could forward a connection from the Strato server trying to reach the WAN side of the perimeter firewall on port 19999 to port 19999 on “intmid” in the DMZ.

Note: If you really do something like this on your firewall you have to be careful to restrict the forwarding to a defined server on the Internet and to close this firewall hole again after the backup procedure. [It makes no sense here to give commands or details as the configuration procedure varies with the type of firewall used.]

However, for this approach to work with openSSH you in addition have to set a parameter for your sshd configuration in the file “/etc/ssh/sshd_config” on “intmid”:

GatewayPorts yes

Otherwise external hosts will not be allowed to use the reverse tunnel. This setting is somewhat dangerous and you should not forget to change it back.

In this approach we couple (local) port forwarding on the PFW with a reverse tunnel from “bup” to “intmid”. The result is basically the same as with two chained reverse tunnels. However, you have to modify your commands on the Strato server somewhat to use port 19999 at the WAN side of your “PFW”. To test the forwarding plus reverse tunnel on the Strato server you would enter:

ssh userid_on_bup@ip_address_of_your_routers_WAN_interface -p 19999

You have to provide the IP address of the WAN interface of your router. Depending on your DSL provider this may change on a daily basis. So you have to find out what it presently is – e.g by the admin interface of your PFW (router) or by asking an external service (e.g. curl icanhazip.com).

All in all I regard the second method as more complicated and potentially also more dangerous than method 1 – because you must not forget to change and change back your sshd configuration on the DMZ host “intmid” and also to reset your PFW configuration. Therefore, I shall only follow the first approach below.

Use rsync to perform the backup

As we have successfully build up tunnels across our firewalls one may think of using “scp” to perform a backup of the server directories. Actually this is not a good idea if you want to make backups of all server directories including system directories. The reason is:

“scp” follows all symbolic links! At least on Opensuse systems this may lead to infinite loops for certain directories whilst copying!

Therefore it is better to use “tar” or “rsync”. See: http://stackoverflow.com/questions/11030394/is-it-possible-to-make-scp-ignore-symbolic-links-during-copy

Personally, I find “rsync” most convenient. And you can combine it
quite easily with SSH! To use the ports defined for our method 1 (with the two chained reverse SSH tunnels) the right syntax for making a backup of e.g. the directory “/var” would be

rsync -avz -e ‘ssh -p 19999’ /var userid_on_bup@localhost:/backups/bup_strato/server_name/

This command has to be performed on the Strato server. Again: Do not get confused by “localhost” – that’s how SSH tunneling works! The “-a” option of the rsync command means “archive mode”. This preserves the mode and user settings of all files and directories throughout the data copying and performs recursions. “z” leads to a transfer of compressed data which will save you time. “/backups/bup_strato/server_name/” represents an example directory on server “bup” where you want to place the backup files of your special Strato server. Of course you should replace it by your own path on your backup server.

Note 1: You have to issue this commands as root on your Strato server to get access to all of the directories there.
Note 2: Please, note that slash “/” at the end of the directory path on the destination system! And note the missing “/” after the local directory “/var”.
Note 3: Please, note the masking of ssh -p 19999 by single quotation marks! [To specify the port by “-p 19999” at the end of the ssh command would not work as you would mix rsync and ssh parameters].
Note 4: The big advantage of rsync naturally is that you only would exchange changed files at the next backup.

Have much fun now with your Strato server and making backups through SSH tunnels!

Heartbleed – kein Ende und dann auch noch Opensuse 12.2

Das ganze Thema “Heartbleed” hält einen aus verschiedenen Gründen in Atem:

Einerseits, weil man nicht weiß, welche Systeme von Online-Diensten, die aktuell in einem Heartbleed-Test als OK gekennzeichnet werden, eigentlich wann genau vom Provider auf den momentan sichereren Stand gebracht wurden. Vielleicht geschah das erst gestern – und vorher war der Serverdienst über Monate hackbar? Auf Webservern mit CM-Systemen, Shops etc. treten die Folgen vielleicht erst künftig zu Tage ….

Es ist deshalb aus meiner Sicht schon aus Vorsichtsgründen erforderlich, alle Passwörter von solchen Diensten, bei denen SSL eine Rolle spielte, schleunigst zu ändern. Die Provider werden kaum in Gänze zugebe, dass sie auch betroffen waren. Bei gehosteten Blogs, CM-Diensten, Shops, … sind zudem umfangreichere Prüfungen auf potentielle ingeschleuste Schadcodes erforderlich. Die Heartbleed-Lücke zu stopfen ist aus meiner Sicht wirklich nur ein erster Schritt zur Schadensbegrenzung.

Der andere Grund sind die im Kundenauftrag verwalteten Server. Was Opensuse anbelangt:

Die betroffenen OpenSSL-Bibliotheken sind auf Opensuse 12.2, 12.3, 13.1 upzudaten, SSL-Zertifikate (Server- wie ggf. Client-Zertifikate) und Passwörter müssen geändert werden. Und der Kunde ist davon in Kenntnis zusetzen. Im Falle von Opensuse 12.3 und 13.1 ist wenigstens das Installieren oder Überinstallieren der aktuellen SSL-RPMs noch auf einfache Weise möglich.

Achtung: Bei den aktualisierten Opensuee-Paket-Versionen für SSL handelt es sich um gepatchte “e”-Versionen und keine “g”-Versionen der Openssl-Bibliotheken/Pakete. Also nicht dadurch verwirren lassen, dass man überall – zuletzt in Mails diverser Provider – liest, dass man unbedingt auf die g-Version upgraden müsse ! Stimmt nicht ! Eine gepatchte frühere Version tut es auch. Nicht nicht vergessen, Apache neu zu starten und danach erneut auf die Heartbleed-Schwäche zu testen!

z.B. über folgende Seite: http://filippo.io/Heartbleed/

Sonderfall Opensuse 12.2:
Leider kann man sich nicht immer aussuchen, wann die eigenen Kunden Geld in die Hand nehmen, um ihre (V-) Server upgraden zu lassen. Das Problem sind auch ein wenig die Provider, wie z.B. Strato. Die hinken mit ihren Angeboten zu virtuellen Servern bei den OS-Paketen dem Entwicklungsstand (vielleicht aus guten Gründen) immer ein ganzes Stück hinterher. V-Server bei Strato wurden z.B. noch vor einem Jahr mit Opensuse 12.2 angeboten. Nach 2 neuen Releases fällt die alte OS-Version aber aus der Update-Wartung durch Suse raus. So kann man mit einem gehosteten V-Server halt schon nach deutlich weniger als 18 Monaten aus dem Wartungsintervall herausfallen. Opensuse 12.2 wird z.B. seit Januar nicht mehr mit neuen Update-Paketen versorgt.

Was kann man nun tun, wenn man noch einen solchen “veralteten” Server verwalten muss?

Zunächst mal versuchen, dem Kunden anhand von “Heartbleed” klarmachen, wie wichtig eine relativ zeitnahe Upgrade- und Maintenance-Politik ist. Es gibt ja auf einem systematisch veraltenden System vermutlich noch viel mehr Schwachstellen als so ein Paradebeispiel wie SSL-Heartbleed. Darunter natürlich auch solche, die erst dann aufgedeckt werden, wenn es keine Updates mehr gibt.

Bekommt man vom Kunden nach einem Überzeugungsgespräch die Zeit und das Geld, so ist zunächst ein Upgrade von 12.2 auf 12.3 am sinnvollsten. Dieser Upgrade funktioniert nach meinen eigenen Erfahrungen relativ schmerzfrei. Ein Upgrade 12.2/12.3 auf 13.1 ist dagegen deutlich schwieriger, da man sich dabei mit einer Rekonfiguration des Apache-Servers herumschlagen muss, die wegen des Umstiegs der aktuellen Apache2 2.4-Version leider unumgänglich wird. Mich hat das damals (Nov. 2013) zumindest einiges an Zeit und Recherchen gekostet, bis die Webserver auf den upgegradeten 13.1-Systemen wieder anstandslos liefen.

Was aber, wenn man
aber kein Geld bekommt, um ein Upgrade durchzuführen?
Nun, dann führt wohl kein Weg an einer eigenen Kompilation des neuen SSL-Paketes aus den Sources inkl. Patch vorbei. Hierfür bietet sich ein Download der gepatchten aktuellen Source-Versionen für Opensuse 12.3 an, die dann gegen Opensuse 12.2 kompiliert werden müssen. Das ist der sicherste und korrekteste Weg. Er funktioniert und er bewahrt einen auch vor evtl. Pfad-Problemen. Die offiziellen Sources von OpenSSL und die zugehörigen Config/Make-Dateien gehen von einem anderen Verzeichnislayout als Opensuse aus.

Ein aus Sicherheitsaspekten deutlich problematischerer Weg besteht darin, Pakete zu nutzen, die von Dritten erstellt wurden. Das ist nicht nur eine Frage des Vertrauens. Programmware aus “privaten” Quell-Repositories zu installieren, ist immer ein potentielles Sicherheitsproblem und erfordert mindestens einen vorherigen Vergleich des (angeblich) verwendeten Sourcecodes gegenüber offiziellen Quellen und weitere nachfolgende Tests. Bei dem Zeitaufwand kann man dann auch schon gleich selbst kompilieren. Na ja, ….

Jedenfalls soll nicht unerwähnt bleiben, dass es unter
http://download.opensuse.org/repositories/home:/
Repositories gibt, die eine gepatchte 12.3 OpenSSL-Paketversion anbieten, die für Opensuse 12.2 kompiliert wurde.

Konkrete Hinweise findet man in
http://forums.opensuse.org/showthread.php/496947-opensuse-12-2-and-ssh-heartbleed/page3

Aber hier muss jeder selber wissen, wie er vorgeht. Bei allem Fluchen über die aktuellen Probleme:

  • Gut finde ich, dass die Sicherheitslücke gefunden wurde.
  • Gut finde ich auch, dass es Leute in der Opensource Community gibt, die sich regelmäßig um Sicherheit kümmern. Denn Lücken durch systematische Tests zu finden, erfordert Zeit und Aufwand. Und für den entsprechenden Einsatz sollte man den Leuten danken.
  • Noch besser finde ich, dass man kurzfristig mit Tipps versorgt wird, was man tun sollte und kann, um die Lücke zu schließen.

Schlecht finde ich nach der aktuellen Erfahrung die kurzen Wartungszyklen der Opensuse-Versionen. Das zeigt, dass die Community zwischenzeitlich immer mal wieder Long Term-Versionen (z.B. mit 3 Jahren Update-Versorgung) bereitstellen sollte.

Ansonsten bleibt mir nur, viel Erfolg beim Prüfen von Logs, Datenbankeinträgen etc. auf den Servern zu wünschen, die der OpenSSL-Verwundbarkeit ausgesetzt waren. Denn SSL setzt man ja z.B. ein, wenn Zugänge und Datentransfers für CM-Systeme etc. abgesichert werden sollten. Wurden die gehackt, so ….

Nachtrag 29.04.2012 :
Die in den vergangenen zwei Wochen in der dt. Presse erschienen Artikel zu Thema Heartbleed finde ich zum Teil unerträglich. Klar, es war ja zu erwarten, dass die Vertreter kommerzieller Closed Source Firmen das zum Anlass nehmen, Open Source zu kritisieren. Aber muss die Presse so unkritisch auf dieser Welle mitschwimmen? Welche Scheinheiligkeit! Als ob kommerzielle Interessen Sicherheit verbessern würden und als ob Entwickler bei kommerziellen Firmen besser und systematischer arbeiten würden als im Opensource Bereich. Nach meinen eigenen Erfahrungen kann man das keineswegs als grundsätzliche Feststellung treffen.
Tja, und man muss eigentlich lange nach Beispielen für Sicherheitsprobleme im kommerziellen Umfeld suchen? Spontan fallen mir ein: Die vielen, fast kontinuierlichen Probleme mit Java in den letzten Jahren, deren sich der kommerzielle Gigant Oracle nur schleppend annahm. Die laufenden Probleme mit dem MS IE und speziell die aktuellen Probleme mit dem MS IE 10. Oder auch: Die gezielte Entkernung von Linux in Bezug auf alle Sicherheitsaspekte bei der frühen Entwicklung von Android durch Google. Oder das Hacking von Linux Servern Anfang 2013, das seinen Ausgangspunkt allerdings in
massiven Fehlern von MS Windows Frontend-Systemen hatte …
Nein, es gibt nun wirklich keinen kausalen Zusammenhang der Art : kommerzielle Firma, Closed Source = Sicherheit. Allen Kritikern sei gesagt: Kehrt vor euren eigenen Haustür.

SSH-Tunnel als Datenbankzugang für gehostete LAMP-Server – I

Einer unserer Kunden will mit LibreOffice Calc/Base direkt auf der Maria/MySQL-Datenbank eines von uns betreuten Linux-LAMP-Servers (unter Opensuse 12.3) arbeiten. Gefordert ist der Datenbankzugang von Opensuse-Linux-Clients wie auch “Windows 7”-Clients aus. Der Server wird bei einem Provider gehostet und für Simulationsberechnungen genutzt. Der Zugang soll aus dem Ausland über das Internet erfolgen. Auf dem Server ist eine Firewall aktiviert. Der Kunde soll die Verbindung selbständig initiieren können.

Ein solches Vorhaben stellt einen vor ein paar sicherheitstechnische Herausforderungen:

  • Da die mit der Datenbank auszutauschenden Daten geschäftsrelevant sind, muss die Verbindung verschlüsselt werden. Hierfür bietet sich SSH an.
  • Da der Server im Internet gehostet ist, wollen wir keinen weiteren Port außer einem für die Server-Administration sowieso erforderlich SSH-Port und einem für Webanwendungen geöffneten HTTPS-Port von außen zugänglich machen.
  • Der Zugang soll nur ganz bestimmten autorisierten Clients zugestanden werden.
  • Kundenmitarbeiter sollen nur den Port 3306 der MariaDB-Datenbank, aber keine anderen Ports ansprechen können.
  • Die unpriviligierten User-Accounts, unter denen Mitarbeiter des Kunden Verbindung zum Server aufnehmen, dürfen keinen Shell-Zugang erhalten und keine Kommandos absetzen können. Im besonderen dürfen sie keine “Reverse SSH Tunnel” vom Server aus aufzubauen.
  • Für Administratoren des Servers erlaubtes SSH Port Forwarding (und damit auch der Aufbau von Reverse SSH Tunnel) darf nicht durch andere Remote Hosts genutzt werden können – auch nicht, wenn die Firewall des Servers mal unten sein sollte.
  • Kundenmitarbeiter sollen keine Files per FTP, SCP etc. auf den Server laden können. X11 Forwarding soll unter SSH nicht erlaubt sein.
  • Für Tests sollen die Kundenmitarbeiter ihre eigenen Maschinen aber durchaus für einen externen Zugang vom Server aus öffnen dürfen. Sie selbst sollen also für Ihre Hosts einen Reverse SSH Tunnel aufbauen und z.B. ihren eigenen SSH-Port auf den Server exportieren dürfen.

Zur Erfüllung der Anforderungen bieten sich folgende Ansätze an:

  • eine SSH-Verbindung – “SSH-Tunnel” – durch die Firewall des Servers,
  • “Lokales Port Forwarding” von bestimmten Client-Systemen des Kunden zum Server,
  • die Etablierung drastischer Einschränkungen für die SSH-Verbindung,
  • die Verhinderung eines Shell Zugangs für die SSH-Nutzer.

Bei all dem gehen wir von “SSH 2”-fähigen Clients und Servern aus.

Angemerkt sei, dass man die ganze Aufgabe ansatzweise auch mit sog. “SSH Reverse Tunnels” (Reverse Port Forwarding) lösen könnte. Dabei würden Ports aktiv vom Server zu definierten Clients exportiert. Ein solches Vorgehen hätte den Vorteil, dass der Zugang vom Server aus eröffnet würde. Dadurch hätte man Kontrolle darüber, wann und zu welchem System die Verbindung aufgebaut wird. Dem entgegen stehen aber etliche praktische, organisatorische Punkte sowie Sicherheitsaspekte. Ein solches Vorgehen ist zudem kaum vereinbar mit der Forderung, dass die Verbindung jederzeit vom Client aus aufgebaut und wieder geschlossen werden können soll. Ich diskutiere deshalb in diesem Blog-Beitrag ein Vorgehen, bei dem ein SSH-basiertes “Local Port Forwarding” von den Kundensystemen aus verwendet wird.

Wir befassen uns dabei vor allem mit Restriktionen der erforderlichen SSH-Konfiguration auf dem Server. Für die geforderten Windows Client zeigen wir in einem
kommenden Teil II ergänzend die PuTTY-Konfiguration für die SSH-Tunnel-Verbindung.

Vorspann: Warum Shell-Zugang und SSH Reverse Tunneling durch die Anwender verhindern ?

Wie viele andere sicherheitsrelevante Tools hat SSH zwei Seiten:

Einerseits eröffnet SSH verschlüsselte Verbindungen zu einem Server oder Host. Dies ist ein Beitrag zur Sicherheit. Andererseits kann SSH aber von kundigen Anwendern auf einem Server oder Host auch dazu genutzt werden, Tunnel durch Firewalls zu graben und die Sicherheit grundlegend zu unterminieren. SSH-Verbindungen, die von einem zu sichernden Server nach außen durch eine Firewall aufgebaut werden können, sind dabei das größte Problem.

Solche Verbindungen können für permanente SSH-Reverse-Tunnel zu externen Maschinen genutzt werden. Dabei wird ein Port des Servers auf die externe Maschine exportiert. Wird ein einmal vom Server aus aufgebauter Reverse SSH-Tunnel später von außen von einem an den Tunnel angebundenen Host genutzt, so wird die Server-Firewall nichts dagegen haben, weil die Nutzung als legitime Antwort auf eine von innen nach außen aufgebaute SSH-Verbindung angesehen wird. Im Zuge eines solchen Tunnels wird gerade die Verschlüsselung zum Problem – es ist im Schadensfall nicht ganz so einfach nachzuweisen, welche Files und Daten durch einen solchen Tunnel vom Server zu Unbefugten transferiert werden.

Die Kombination von Shell-Zugang und SSH-Fähigkeit für Nutzer eines (gehosteten) Servers steht daher im direkten Gegensatz zum Schutz des Servers vor eingehenden Verbindungen von außen. Hierbei nutzt es übrigens auch nichts, den SSH-Port für eine Verbindung vom Server nach außen durch eine Firewall zu sperren – ein SSH-berechtigter Benutzer kann z.B. auch einen nach außen offenen HTTPS-Port (443) für SSH-Operationen nutzen. Meine Devise ist daher:

SSH ist für die meisten regulären Benutzer zu schützender Systeme grundsätzlich nicht zuzulassen – im besonderen nicht mit der Option, Ports “forwarden” zu dürfen.

Wir befinden uns deshalb in einem Dilemma, denn unseren externen Kunden-Mitarbeitern müssen wir einen SSH-Zugang mit Port-Forwarding zugestehen. Wir lösen das Dilemma dadurch, dass diese User auf dem Server weder mit Hilfe von SSH noch sonstwie Kommandos absetzen, noch dass sie persönliche “ssh_config” anlegen oder modifizieren können:

Externen Anwendern, denen ein SSH-Zugang zu einem bestimmten Service (Port) eines zu schützenden, gehosteten Servers gewährt wird, darf in keinem Fall ein (SSH-) Zugang zu einer Shell eingeräumt werden. Externe Anwender mit SSH-Tunnel-Zugang sind ja de facto User auf dem Server, denen die SSH-Verbindung explizit – und wie wir sehen werden, mit “Port Forwarding” – zugestanden wird. Ein solcher SSH-Benutzer mit Shell-Zugang würde eine echte Gefahr für die Sicherheit darstellen. Sie sollen mit SSH deshalb ausschließlich einen Tunnel von ihren Hosts zum Server aufbauen können (Local Port Forwarding). Sonst nichts ….

Einschränkung des Zugangs auf bestimmte Clients

Die Begrenzung des des SSH-Zugangs auf bestimmte Clients haben wir durch folgende Maßnahmen erreicht:

  • "Umkonfiguration" des SSH-Zugangs auf eine gegenüber dem Standard modifizierte Port-Nummer. Den Clients muss diese Nummer bekannt sein. [Kein echter Schutz, aber eine erste Hürde für Angreifer und Skript-Kiddies … siehe die Anmerkung weiter unten]
  • Einschränkung des Serverzugangs auf genau diesen einen Port (neben https) über eine Firewall.
  • Einschränkungen des SSH-Zugangs auf bestimmte IP-Client-Adressen über eine
    entsprechend konfigurierte Firewall.
  • Vollständiger Ersatz des passwort-basierten Zugangs durch eine Authentisierung der Clients gegenüber dem Server, die auf asymmetrischen SSH-RSA-Schlüsseln beruht.

Auf die genaue Firewall-Konfigurationen gehe ich hier nicht ein. Die eingesetzte Firewall schottet sämtliche anderen Ports komplett ab. Angemerkt sei auch, dass wir außer HTTPS-Verbindungen, DNS- und NTP-Verbindungen zu ganz bestimmten Hosts im Internet keine vom Server initiierte Verbindungen nach außen zulassen.

Wie man den ersten und letzten Punkt der obigen Liste (Portmodifikation, schlüsselbasierte Authentifizierung) realisiert , kann man u.a. in entsprechenden Blog-Artikeln zur Konfiguration eines gehosteten (virtuellen) Strato-V-Servers nachlesen:

Strato-V-Server mit Opensuse 12.3 – II – Installation / SSH-Port ändern
Strato-V-Server mit Opensuse 12.3 – III – Stop SSH Root Login
Strato-V-Server mit Opensuse 12.3 – IV – SSH Key Authentication

Siehe aber auch die Links zur schlüsselbasierten Authentifizierung am Ende des Artikels. Der Vorteil von schlüsselbasierten Zugangsverfahren ist die Kombination aus Besitz eines Schlüssels mit einer zusätzlichen Passphrase auf den Client-Systemen. Systeme und User, die über das eine oder andere nicht verfügen, erlangen keinen Zugang zum Server – soweit das asymmetrische Schlüselverfahren selbst keine Backdoors beinhaltet.

Eine Warnung erscheint mir dennoch angebracht:

Eine schlüsselbasierte Zugangsbeschränkung ist im Sinne eines berechtigten Datenzugangs nur genau soweit sicher, als sie den Benutzern, denen die Private Keys zugeordnet werden, trauen können. Verbreiten diese User Ihre Keys, so ist gegen den Datenbank-Zugang anderer externer User kein Kraut gewachsen. Eine Sicherheitsbelehrung mit Androhung entsprechender Sanktionen ist sicher sinnvoll. Für technisch komplexere Lösungen, bei denen die User des Tunnels selbst keinen direkten lesenden Zugang auf zugeordnete “Private Keys” mehr erhalten sollen, siehe den entsprechenden Link im letzten Abschnitt dieses Artikels.

Diese potentielle Gefahr der Schlüsselweitergabe macht es umso mehr erforderlich, weitere Barrieren hochzufahren. Das betrifft zum einen die sowieso erforderliche Verhinderung des Shell-Zugangs der externen SSH-Tunnel-User – aber auch drastische Beschränkung der Userberechtigungen auf der Datenbank selbst. Sich die Rechte auf der Datenbank genau zu überlegen und auf ein Minimum zu beschränken, gehört zum ganzen Setup unbedingt dazu! Auch wenn wir in diesem Artikel nicht darauf eingehen..

Eine Anmerkung noch zur vorgenommenen Verlagerung des SSH-Ports :
Unter bestimmten Bedingungen – z.B. bei aktiven Usern, die Shell-Zugang auf dem LAMP-Server haben – kann es problematisch werden, SSH auf einen unpriviligierten Port zu verschieben. Siehe hierzu den Artikel und die interessante Diskussion unter
 
why-putting-ssh-on-another-port-than-22-is-bad-idea
 
Aber:  

Wenn es auf dem zu schützenden LAMP-Server keinen normalen User neben dem Admin gibt, der einen unpriviligierten Port nach außen öffnen kann, sehe ich die im angegebenen Artikel diskutierten Gefahren nicht. Die Gefahr einer Umlenkung eines bereits belegten Ports von außen ist unter den in diesem Artikel dargestellten Bedingungen auch nicht gegeben. Somit dient die Port-Änderung einer Abschwächung des ansonsten stattfindenden
externen Dauerbeschusses auf Port 22 oder andere priviligierte Ports durch Verschleierung (“Obfuscating”). Man muss sich allerdings darüber im Klaren sein, dass sukzessive Stealth Portscans (ggf. von verschiedenen Systemen) aus, früher oder später zur Entdeckung des offenen Ports führen werden und damit auch zu Versuchen eines SSH-Zugangs über diesen Port. Dann müssen andere Sicherheitsmaßnahmen greifen – wie eben z.B. die Authentifizierung per Keys und andere Vorkehrungen. “Obfuscating” allein bietet keinen Schutz, sondern stellt maximal eine erste kleine Hürde in einer Kette von Schutzmaßnahmen dar.

Globale Optionen in der Konfigurationsdatei /etc/ssh/sshd_config des Servers

Der Server heiße “kundenserver.de“. Wir setzen nachfolgend voraus, dass der SSH-Zugang auf SSH-Schlüsselpaaren beruht und dem Server alle Public SSH-Keys der zugelassenen Remote-User bekannt sind (Dateien “~/.ssh/authorized_keys”) . Wir haben uns – schon aus Logging-Gründen – dazu entschlossen, den SSH-Zugang für die Kundenmitarbeiter auf mehrere (eingeschränkte) Accounts auf dem Server zu verteilen. Eine Lösung, bei der sich mehrere User des Kunden über genau einen User-Account des Servers einloggen, haben wir verworfen. Auch die Datenbank-User wurden getrennt. Es gibt Vor- und Nachteile beider Lösungen. Beim hier gewählten Verfahren sind u.a. mehr Accounts und ggf. auch Schlüssel zu verwalten. Da es nur um 3 User (“kundea”, “kundeb”, “kundec”) geht, ist der Aufwand aber erträglich.

Wir nutzen nun globale Optionen in der Datei “/etc/ssh/sshd_config” auf dem Server, um einen root-Zugang über SSH zu verhindern und andererseits den SSH-Zugang von außen auf die ausgewählten Kundenmitarbeiter zu beschränken. Ferner wird eine Nutzung von X11 unterbunden. Der offene SSH-Port habe als Beispiel die Nummer "6XXXX". Es ergeben sich dann folgende Einträge in der sshd_config:

Auszug /etc/ssh/sshd_config“:

Port 6xxxx
PermitRootLogin no
AllowUsers kundea kundeb kundec
RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no
X11Forwarding no
GatewayPorts no
UsePrivilegeSeparation sandbox
PermitTunnel no
AllowAgentForwarding no
AllowTcpForwarding no
#Subsystem sftp /usr/lib/ssh/sftp-server

Kundige Leser werden sich an dieser Stelle über die Option “AllowTcpForwarding no” wundern. Wir heben diese globale Beschränkung weiter unten user-bezogen wieder auf.
Man beachte auch die Auskommentierung des letzten Eintrags. Es werden keine SSH-Subsysteme wie SFTP zugelassen.

Wir erweitern weiter unten unsere SSH-Einschränkungen noch und gehen dabei auch auf die Einstellung “GatewayPorts no” und “AllowAgentForwarding no” ein.

Testen des SSH-Tunnels vom Linux-Client aus

Nehmen wir an, einer der User unseres Kunden, der Zugang zum (Datenbank-) Server erhalten soll, habe auf unserem Server “kundenserver.de” den Account "kundea". Auf seinem eigenen Linux-Host “kundensystema” habe der Kunde dagegen einen Account “kunda”. Der Host “kundensystema” fungiert als SSH-Client bzgl. des SSH-Servers “kundenserver.de”. Der für unseren Server benutzte “Private SSH RSA Keys” des Users sei auf “kundensystema” in der Datei

~/.ssh/id_a_kundenserver

hinterlegt. Dort gebe es aber noch andere Private
Key Files für andere Server.

Es gelte ferner die Einschränkung, dass der lokale Port "3306" des Linux-Clients “kundensystema” schon durch eine lokale MySQL-Datenbank belegt sei. Der Port "3307" sei dagegen frei. Welches Kommando ist dann auf dem Linux-System “kundensystema” von “kunda” erforderlich, um per SSH-Tunnel auf die Datenbank zu kommen?

Auf der Kommandozeile einer Linux Bash Shell kann man zum Aufbau des benötigten Tunnels Folgendes eingeben:

kunda@kundensystema :~> ssh    -fN   -L3307:127.0.0.1:3306 \
> kundea@kundenserver.de    -p 6xxxx    -i ~/.ssh/id_a_kundenserver

(Der Backslash steht für den Zeilenumbruch auf der Kommandozeile !)
“kunda” sollte nun nach der Passphrase des Private Keys gefragt werden. Nach korrekter Eingabe steht der Tunnel durch die Firewall zum Port 3306 des Servers:

Der lokale Client-Port 3307 wird auf dem Server “kundenserver” über den auf Port 6xxxx eröffneten SSH-Tunnel auf den dortigen Port 3306 umgelenkt. Letzteres geschieht quasi durch die aktive Firewall des Servers hindurch. Benötigt wird von außen nur der Zugang zum Port “6xxxx” der SSH-Verbindung.

Zu den Optionen

"-f" ( SSH Prozess wird in den Hintergrund verschoben)

und

"-N" ( “do not execute a remote command” – nur Tunneling !)

ps -aux | grep ssh -fN

und nachfolgendem Identifizieren der PID des ssh-Prozess plus

kill -15 PID

Für andere Verfahren zur (skriptbasierten) Beendigung siehe die Links unten.

Testen des Tunnels zur Datenbank mittels “mysql”

Wir wollen nun testen, ob wir vom Host des Kunden aus wirklich über den zuvor geöffneten “Tunnel” zur Datenbank des Servers kommen. Hierzu nutzen wir das Kommandozeilentool "mysql". Der Datenbankaccount für diesen User auf dem Server “kundenserver.de” heiße "sqlkundea".

Unter Linux müssen wir bzgl. des Testens der Remote-Verbindung übers Internet eine kleine Falle umgehen. Es gibt nämlich bzgl. des Zugangs zu einer MySQL-Datenbank einen Unterschied zwischen “localhost” und “127.0.0.1”:

Tools wie mysql versuchen unter Linux bei Angabe von “localhost” eine Verbindung über einen (schnelleren) lokalen UNIX-Domain-Socket statt einer Netzwerk-TCP/IP-Verbindung zum Datenbank-Daemon. [Unter Windows wird dagegen immer eine TCP/IP-Verbindung geöffnet.]

Im hier besprochenen Port-Umlenkungsfall ist eine TCP/IP-Verbindung zur Bank des Servers auch unter Linux zu konfigurieren. Bei Angabe der IP-Adresse 127.0.0.1 wird eine solche geöffnet. Siehe auch:

http://stackoverflow.com/questions/3715925/localhost-vs-127-0-0-1
http://stackoverflow.com/questions/9714899/php-mysql-difference-between-127-0-0-1-and-localhost
http://stackoverflow.com/questions/16134314/mysql-connect-difference-between-localhost-and-127-0-0-1

Beim Testen auf der Kommandozeile der “bash” empfiehlt es sich also,

kunda@
kundensystema :~>mysql   -h 127.0.0.1   -u sqlkundea   -p

anstatt “… -h localhost…” anzugeben. Steht der Tunnel und haben wir alles richtig gemacht, so gelangen wir (genauer “kunda” auf “kundensystema”) nach Eingabe des Datenbank-Zugangspassworts auf den MariaDB/MySQL-Service “auf kundenserver.de” :

kunda@kundensystema:~> mysql -P 3307 -h 127.0.0.1 -u sqlkundea -p
Enter password:

Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 7308
Server version: 5.5.33-MariaDB openSUSE package
 
Copyright (c) 2000, 2013, Oracle, Monty Program Ab and others.
 
Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement.
 
MariaDB [(none)]>

Dass man wirklich auf dem Server-RDBMS und nicht einem lokalen MySQL-RDBMS gelandet ist, ergibt sich entweder bereits aus dem server-spezifischen Passwort oder einem anschließenden “connect” zu einer speziellen, nur auf dem Server existierenden Bank.

Weitere Restriktionen auf dem Server – Verhindern des Absetzens von Kommandos

Bislang haben wir zusätzlich zum schlüsselbasierten Zugang lediglich die Firewall des Servers per SSH-durchtunnelt, um an den dortigen 3306-Port zu gelangen. Der User “kundea” kann sich mit den obigen Konfigurationseinstellungen aber noch ganz normal in eine SSH-Shell einloggen und Kommandos absetzen.

kunda@kundensystema:~>ssh kundea@kundenserver.de    -p 6xxxx \
> -i ~/.ssh/id_a_kundenserver
Enter passphrase for key ‘/home/kundea/.ssh/id_a_kundenserver’:
Last login: Mon Nov 11 09:18:42 2013 from kundensystem.de
Have a lot of fun…
kundea@kundenserver:~>

Das und weitere Dinge wollen wir nun unterbinden. Das kann man in einem ersten Schritt z.T. durch globale Vorgaben in der “/etc/ssh/sshd_config” erreichen. Wir zeigen zur Abwechslung aber mal ein userspezifisches Vorgehen. Es gibt zwei Methoden, userspezifische Restriktionen des sshd-Daemons auf dem Server wirksam zu machen:

  • Zentrale Einstellungen in der Konfigurationsdatei “/etc/ssh/sshd-config”.
  • “Public Key”-spezifische Restriktionen in den Files “~/.ssh/authorized_keys” derjenigen Accounts über die der Zugang (hier zum Datenbank-Port) erfolgen soll.

Ich gehe in diesem Beitrag genauer nur auf die erste Variante ein. Man kann die kommenden Restriktionen aber auch den spezifischen Schlüsseln voranstellen, die man in der Datei

~/.ssh/authorized_keys

des Users bzw. derjenigen User auf dem Server, über dessen Account bzw. der Datenbankzugang erfolgen soll, untergebracht hat. Siehe hierzu die Links am Ende des Artikels.

Wir wollen Restriktionen exemplarisch und userspezifisch für den Account “kundea” auf dem Server vornehmen. Für userspezifische Festlegungen in der sshd_config gibt es die Vorgabe “Match User” – hier für unsere Kundenmitarbeiter

Match User kundea kundeb kundec

Siehe hierzu und für andere Varianten von “Match” (z.B. für Usergruppen):
http://linux.die.net/man/5/sshd_config

Ich zitiere zu “Match”:

Introduces a conditional block. If all of the criteria on the Match line are satisfied, the keywords on the following lines override those set in the global section of the config file, until either another Match line or the end of
the file.

Hinter dem “Match”-Statement kann man also Optionen für die SSHD-Parameter angeben, die sich dann userspezifisch auswirken. Unter OpenSSH sind Vorgaben für folgende Parameter möglich:

AllowAgentForwarding, AllowTcpForwarding, Banner, ChrootDirectory, ForceCommand, GatewayPorts, GSSAPIAuthentication, HostbasedAuthentication, KbdInteractiveAuthentication, KerberosAuthentication, KerberosUseKuserok, MaxAuthTries, MaxSessions, PubkeyAuthentication, AuthorizedKeysCommand, AuthorizedKeysCommandRunAs, PasswordAuthentication, PermitEmptyPasswords, PermitOpen, PermitRootLogin, RequiredAuthentications1, RequiredAuthentications2, RhostsRSAAuthentication, RSAAuthentication, X11DisplayOffset, X11Forwarding and X11UseLocalHost.

Außerhalb der userspezifischen Festlegungen für diese Parameter gelten die globalen Einstellungen. Man nimmt userspezifische Einschränkungen am Ende des Konfigurationsfiles vor. Für die von uns geforderten Einschränkungen sind vier Parameter relevant:

Match User kundea kundeb kundec
#X11Forwarding no
#PermitTunnel no
#GatewayPorts no
 
AllowTcpForwarding yes
PermitOpen 127.0.0.1:3306    localhost:3306
AllowAgentForwarding no
ForceCommand echo ‘This account can only be used for tunneling’

Die auskommentierten Statements geben dabei ergänzend einige Standardeinstellungen von OpenSSH oder von uns explizit vorgenommene globale Einstellungen wieder (s.oben).

Zur Option “AllowTcpForwarding”

Nicht einzuschränken ist an dieser Stelle für die Kunden-Mitarbeiter die Option “AllowTcpForwarding”. Ein Abschalten dieser Option würde jedes Port-Forwarding unterbinden – auch das gewünschte “Local Port Forwarding” unserer Kunden zum Server selbst ! Da wir global kein Port-Forwarding zugelassen haben (auch um Reverse Tunneling zu unterbinden), müssen wir es jetzt user-spezifisch erlauben:

AllowTcpForwarding yes

Zur Option “PermitOpen”

Ich zitiere aus den man-Seiten :

PermitOpen: Specifies the destinations to which TCP port forwarding is permitted. The forwarding specification must be one of the following forms:
 
    PermitOpen host:port
    PermitOpen IPv4_addr:port
    PermitOpen [IPv6_addr]:port
 
Multiple forwards may be specified by separating them with whitespace. An argument of “any” can be used to remove all restrictions and permit any forwarding requests. By default all port forwarding requests are permitted.

Dass hier “host” und “port” anzugeben sind, hat damit zu tun, dass das SSH-Port-Forwarding ja nicht zwingend auf unseren Server selbst als Zieladresse beschränkt sein muss, sondern dieser auch als Sprungbrett zu jedem beliebigen anderen Host, zu dem der Server Zugang hat, genutzt werden kann. Wir wollen das Forwarding aber aus Perspektive des angesprochenen SSH-Servers genau auf ihn selbst – also “localhost” – und den Port 3306 begrenzen.

Wir geben in der sshd_config deshalb beide Varianten der localhost-Definition – einmal “wörtlich” und einmal über das Loopback-Interface – an, um unter Windows und Linux den Unterschied, den MySQL-Tools bzgl. des Zugangs evtl. machen, sicher hantieren zu können.

Zur Option “AllowAgentForwarding”

Ich zitiere aus den man-Seiten :

AllowAgentForwarding:
r
Specifies whether ssh-agent(1) forwarding is permitted. The default is “yes”. Note that disabling agent forwarding does not improve security unless users are also denied shell access, as they can always install their own forwarders.

Man kann den Server beim Aufbau einer SSH-Verbindung veranlassen, weitere Keys für Verbindungen zu weiteren Servern aus einem lokal auf dem SSH-Client-System laufenden SSH-Key-Agent auszulesen. Der Server könnte dann als Zwischenstation für Verbindungen zu anderen Servern missbraucht werden. Nicht immer können wir über eine Firewall alle Verbindungen nach außen auf nur wenige Adressen einschränken. Und auch eine Firewall muss ggf. mal abgeschaltet werden. Dann schützt die obige Angabe trotzdem gegen clientbasiertes AgentForwarding.

Zur Option “ForceCommand”

Ich zitiere aus den man-Seiten :

ForceCommand:
Forces the execution of the command specified by ForceCommand, ignoring any command supplied by the client. The command is invoked by using the user’s login shell with the -c option. This applies to shell, command, or subsystem execution. The command originally supplied by the client is available in the SSH_ORIGINAL_COMMAND environment variable.

Damit können wir die Kundenmitarbeiter daran hindern, auf dem Server Kommandos abzusetzen:

ForceCommand echo ‘This account can only be used for tunneling’

Test:

kunda@kundensystema:~> ssh kundea@kundenserver.de    -p 6xxxx \
> -i ~/.ssh/id_a_kundenserver
Enter passphrase for key ‘/home/kunde/.ssh/id_rsa’:
This account can only be used for tunneling
Connection to kundenserver.de closed.

Gibt an “-v” als zusätzliche ssh-Option an, so sieht man einen Exit Code 0. Das echo-Kommando wurde fehlerfrei ausgeführt. Mehr ist aber für den Kunden nicht möglich. Trotzdem kann er mit dem Kommando

kunda@kundensystema :~> ssh    -fN    -L3307:127.0.0.1:3306 \
> kundea@kundenserver.de    -p 6xxxx    -i ~/.ssh/id_a_kundenserver

nach wie vor den gewünschten Tunnel zur Datenbank aufbauen. (Übrigens: Man kann mit “ForceCommand” in anderen Szenarien viele hübsche Dinge machen, z.B. einen 2 Phasen Login basteln oder den externen User auf genau ein Programm wie etwa “svn” umlenken, etc. . Es lohnt sich wirklich, damit ein wenig zu experimentieren. )

Entzug des Shell-Zugangs

Trotz des Einsatzes von “ForceCommand” sind wir noch nicht ganz zufrieden. Ich sehe es als wichtig an, dem User jedes Recht zu nehmen, sich in eine bedienbare Shell auf dem Server einzuloggen. Ein ggf. später hinzukommender normaler User auf dem Server könnte z.B. versuchen, die Accounts von “kundea”, “kundeb”, “kundec” auf dem Server zu hacken und unter Ihrem Namen einen Reverse SSH Tunnel aufzubauen. Auch das wollen wir verhindern. Dazu muss der Shell-Zugang völlig unterbunden werden. Fehler beim Hochfahren von SSH oder der Konfiguration von SSH sollen nicht ausgenutzt werden können.

Dies erreichen wir als Admin durch :

kundenserver.de:~ # usermod   – s /bin/false    kundea

und analog für die anderen Accounts. Dies führt zu folgendem Verhalten:

kunda@kundensystema:~> ssh kundea@kundenserver.de    -p 6xxxx   \
> -i ~/.ssh/id_a_kundenserver
Enter passphrase for key ‘/home/kunde/.ssh/id_rsa’:

Connection to h2215102.stratoserver.net
closed.
kunda@kundensystema:~>

Verwenden wir wieder die Option “-v”, so erkennen wir, dass der Exit Code diesmal “1” ist:

debug1: Exit status 1

Selbst das Absetzen des “echo”-Kommandos schlägt jetzt fehl und die angestrebte SSH-Verbindung wird abgebrochen. Dennoch ist es mit der Option “-fN” immer noch erfolgreich möglich, den Tunnel zur Datenbank herzustellen. Das zugehörige Kommando

kunda@kundensystema :~> ssh    -fN    -L3307:127.0.0.1:3306   \
> kundea@kundenserver.de    -p 6xxxx    -i ~/.ssh/id_a_kundenserver

wird anstandslos ausgeführt. Testen kann man den Tunnel natürlich wie oben gezeigt mittels des”mysql”-Tools. Es steht nun weiteren Experimenten mit anderen Datenbank-Tools wie z.B. phpMyAdmin oder BASE aus der LibreOffice-Suite über den Tunnel hinweg nichts mehr im Wege.

Zur Option “GatewayPorts no” auf den SSH-Client-Systemen und dem Server

Zusätzlich checken wir zur Sicherheit, dass sowohl auf den SSH-Client-System “kundensystema”, “kundensystemb”, etc. und auch dem Server die globale Option

GatewayPorts no

wirklich auf “no” gesetzt ist.

Auf den Client-Systemen ist die für die Konfiguration zuständige Datei

/etc/ssh/ssh_config

Dort setzen wir explizit die Option

GatewayPorts no

Zusätzlich setzte der Kunden-Admin dies auch noch in der “sshd_config” der Hostsysteme beim Kunden. Diese Maßnahme dient zum Schutz unserer Kundensysteme, aber auch zum Schutz des Servers:

Die genannte Option steuert, ob andere Hosts mit Verbindung zu den Kundensystemen Zugang zum dort umgeleiteten Port 3307 bekommen sollen oder nicht. Endpunkte von TCP Verbindungen (Sockets !) werden auf Linux-Systemen typischerweise an alle Netzwerkinterfaces gebunden. Die obige Option verhindert das und bindet den (umzulenkenden) Port, auf den das jeweilige Kundensystem hört, ausschließlich an dessen Loopback-Interface. Das Loopback-Interface ist danach nur lokal zugänglich. Damit ist es für externe Hosts und deren User nicht mehr möglich, über Interfaces, die unsere SSH-Client-Systeme mit dem Rest der ihnen zugänglichen Welt verbinden, den Port zu nutzen, der zu unserem Server ge-“forwarded” wird.

Dies verhindert allerdings noch nicht, dass eventuelle andere kundige lokale Benutzer von “kundensystema” diesen umgeleiteten Port nutzen können. Aber ein Unterbinden der Nutzung des Datenbankports durch lokale Nutzer des Servers muss man auf anderem Wege – wie etwa den Einsatz der Keyfiles – erreichen.

Ein Seitenblick auf “Local Port Forwarding” vom Server zu den Client-Systemen
Warum “GatewayPorts no” auf dem Server? Sind mehrere Administratoren auf dem Server aktiv, könnte einer von Ihnen auf den Gedanken kommen, für Tests SSH-Verbindungen vom Server zu definierten Client-Systemen aufzunehmen. Dann würde er ggf. “Local Port Forwarding” zu den Client-Systemen nutzen, die diesen Zugang erlauben. Eine Nutzung umgelenkter Serverports zu irgendwelchen Clients soll natürlich unter keinen Umständen für externe Hosts möglich sein. Und da meinen wir nicht nur die Hosts der Kunden. Wir setzen daher zur Sicherheit auch in der “/etc/ssh/sshd_config” des Servers explizit die Option

GatewayPorts no

Wir hatten ja bereits angemerkt, dass der Server gegen Zugriffe von außen durch eine Firewall geschützt werden soll. Warum also diese explizite Einschränkung? Hierfür gibt es zwei Gründe:

  1. Auf gehosteten Servern gibt es immer mal wieder Situationen, in denen mit der Firewall kurzfristig gearbeitet und ggf. experimentiert werden muss.
    Die vorgenommene Einstellung schützt dann unabhängig von der Firewall.
  2. Auf gehosteten und remote verwalteten Systemen kann es als Notanker erforderlich sein, einen über Verwaltungsoberflächen des Hosters vorgenommenen Reboot ohne unmittelbaren Start von Firewall-Skripten ablaufen zu lassen. Die FW und weitere Server-Dienste werden dann nur zeitverzögert hochgefahren. In der Zwischenzeit steht dann (nur) der modifizierte SSH-Port bereit – aber ohne weitere, zusätzlich Firewall-Einschränkungen. Nach einem Reboot schützt die obige Einstellung auch innerhalb des gewährten Zeitintervalls ohne Firewall.

An solche Szenarien muss man u.U. dann denken, wenn man viel unterwegs ist und man im Notfall auch von einem fremdem System aus unbedingt Zugang zum Server bekommen muss.

Fazit

Wir haben durch die geschilderten Einstellungen alle anfänglich genannten Ziel erreicht. Dass der Kunde über einen Reverse-Tunnel von seinem eigenen Host aus einen eigenen Port auf einen unbesetzten Port des Servers exportieren kann, kann der Leser selbst testen. Hierbei ergibt sich die interessante Frage, ob er dadurch einen bereits besetzten Port übernehmen kann. Dies ist nicht der Fall – zumindest nicht, wenn es nur genau ein Netzwerk-Interface nach außen gibt.

Es ist also möglich, einen kryptierten SSH-Tunnel mit Local Port Forwarding zur MySQL/MariaDB-Datenbank auf einem gehosteten Server (mit Firewall) einzurichten. Gerade die unglaubliche Flexibilität von SSH beim Untergraben von Firewalls macht aber etliche Sicherheitsvorkehrungen im Umfeld der eigentlichen Tunnelverbindung unerlässlich. Aber auch nach dem erforderlichen Unterbinden des Shell-Zugangs auf dem Server können unsere Kunden immer noch den gewünschten reinen Tunnel zur Datenbank aufbauen und nutzen.

Bleibt noch anzumerken, dass man den Kundenmitarbeitern das Arbeiten natürlich noch etwas erleichtern kann, indem man die Port-Forwarding-Optionen in deren ~/.ssh/ssh_config”-Dateien verankert. Zudem wird man – je nach Sicherheitsphilosophie des dortigen Admins ggf. auch “SSH-Agents” einsetzen, damit die Passphrase für das Auth-Key-File nicht so oft eingegeben werden muss. Ferner kann man an Skripts zum vereinfachten Tunnelaufbau denken. Hier ist intensive Kooperation mit dem Kunden-Admin erforderlich.

Im nächsten Beitrag zum getunnelten Datenbankzugang gehe ich auf die erforderliche PuTTY-Konfiguration für potentielle Windows 7 Clients ein.

Links

Key-basierte Authentifizierung
http://linuxwiki.de/OpenSSH
http://sourceforge.net/apps/trac/sourceforge/wiki/SSH%20keys
http://www.lofar.org/wiki/doku.php?id=public:ssh-usage
http://www.ceda.ac.uk/help/users-guide/ssh-keys/
http://docstore.mik.ua/orelly/networking_2ndEd/ssh/ch09_02.htm
http://docstore.mik.ua/orelly/networking_2ndEd/ssh/ch08_02.htm
http://en.wikibooks.org/wiki/OpenSSH/Cookbook/Authentication_Keys
http://www.eng.cam.ac.uk/help/jpmg/ssh/authorized_keys_howto.html

Sicherung gegen Kopieren der Private Keys
Alles andere als einfach. In Unternehmen muss man ggf. zu Lösungen greifen, die zentrale Gateway-Server als Custodians für die SSH-verbindungen einsetzen. Eien entsprechende Lösung ist hier beschrieben:

http://stackoverflow.com/questions/9286622/protecting-ssh-keys
http://martin.kleppmann.com/2013/05/24/improving-security-of-ssh-private-keys.html

SSH-Tunneling und Restriktionen
http://docstore.mik.ua/orelly/networking_2ndEd/ssh/ch09_02.htm#ch09-17854.html
http://www.debianadmin.com/howto-use-ssh-local-and-remote-port-forwarding.html
http://en.wikibooks.org/wiki/OpenSSH/Cookbook/Tunnels
http://bioteam.net/2009/10/ssh-tunnels-for-beginners/
http://bioteam.net/2009/11/ssh-tunnels-part-3-reverse-tunnels/
http://snajsoft.com/2009/02/12/prevent-reverse-ssh/
https://raymii.org/s/tutorials/Autossh_persistent_tunnels.html
http://www.spencerstirling.com/computergeek/sshtunnel.html
http://freddebostrom.wordpress.com/2009/04/10/ssh-tunnel-from-the-command-line/

Breaking Firewalls with OpenSSH and PuTTY
Bypassing corporate firewall with reverse ssh port forwarding
How to Lose your Job with SSH, part 1

How to create a restricted SSH user for port forwarding?
http://superuser.com/questions/516417/how-to-restrict-ssh-port-forwarding-without-denying-it
http://blog.e-shell.org/288
http://serverfault.com/questions/494466/how-to-restrict-ssh-tunnel-authority-to-a-certain-port
http://webdevwonders.com/configuring-a-permanent-ssh-tunnel-for-mysql-connections-on-debian/

Agent-basiertes Forwarding
An Illustrated Guide to SSH Agent Forwarding

Zeitlimits:
http://unix.stackexchange.com/questions/3026/what-does-the-options-serveraliveinterval-and-clientaliveinterval-in-sshd-co

Restriktionen im File ~/.ssh/authorized_keys
http://www.eng.cam.ac.uk/help/jpmg/ssh/authorized_keys_howto.html
http://security.stackexchange.com/questions/34216/how-to-secure-ssh-such-that-multiple-users-can-log-in-to-one-account
http://superuser.com/questions/516417/how-to-restrict-ssh-port-forwarding-
without-denying-it

https://www.itefix.no/i2/content/openssh-tunnels-allow-deny-single-users

Tunnel automatisch öffnen und schließen
https://www.linuxnet.ch/bash-script-that-open-and-close-an-ssh-tunnel-automagically/
http://fixunix.com/ssh/73788-how-kill-background-ssh-process.html

Strato-V-Server mit Opensuse 12.3 – IV – SSH Key Authentication

Im letzten Beitrag dieser Serie

Strato-V-Server mit Opensuse 12.3 – III – Stop SSH Root Login

hatten wir den SSH-Zugang über einen bereits verschobenen Port nur noch einem bestimmten unpriviligierten User [Bsp: “xtarjax”] zugestanden und den SSH-Zugang für root deaktiviert.

In diesem Beitrag ersetzen wir den normalen SSH-Login mit passwort-basierter Authentisierung durch eine Authentifizierung, bei der asymmetrische SSH-Schlüssel benutzt werden. Der Sicherheitsgewinn, den wir uns dadurch versprechen ist der, dass ein Login ab jetzt nur noch personalisiert und von Systemen aus möglich ist, auf denen

  • ein File mit dem privaten Schlüssel existiert,
  • eine Passphrase zur Aktivierung des Schlüssels bekannt ist.

Der verschobene SSH-Port ist dann auf dem Server zwar noch offen, aber ein Zugang geht nicht mehr von überall her und nicht mehr über die Angabe einer User-Id und eines Passworts. Wir zeigen die erforderlichen Schritte auf einem Linux-Client und dem Server.

Schlüsselgenerierung auf einem Opensuse-Client

Als normaler User erzeugen wir uns ein SSH-Schlüsselpaar mittels des Befehls “ssh-keygen”. Ohne Parameter aufgerufen, wird durch ssh-keygen ein RSA-Schlüsselpaar mit je 2048 Bit Länge für SSH2 erzeugt:

mysystem:~> ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/myself/.ssh/id_rsa): /home/myself/.ssh/id_rsa
Enter passphrase (empty for no passphrase):
Enter same passphrase again: 
Your identification has been saved in /home/myself/.ssh/id_rsa.
Your public key has been saved in /home/myself/.ssh/id_rsa.pub.
The key fingerprint is:
77:1a:cb:72:6b:00:5a:22:7d:34:85:11:a4:5e:28:ea myself@mysystem.mydomain.de
The key's randomart image is:
+--[ RSA 2048]----+<br>
|         .++     |<br>
|         ....    |<br>
|        . +.     |<br>
|  .   .o o..     |<br>
|   o .o.S.       |<br>
|    +..*  .      |<br>
|    .+= S.      |<br>
|     oo..        |<br>
|     ...         |<br>
+-----------------+<br>
mysystem:~>

Bei höheren Ansprüchen kann man die Schlüssellänge (z.B. 4096 Bit) entsprechend vorgeben. Man benutzt dazu die Option “-b” (s. die man-Seite).

Hinweis 1:
Hat man bereits mehrere private SSH-Schlüssel für unterschiedliche Zwecke generiert, so muss man die Key-Files natürlich unter anderen Namen anlegen lassen, um ein Überschreiben des vorhandenen Keys zu vermeiden. Abweichende Namen setzen dann ggf. beim Aufnehmen der SSH-Verbindung die Option “-i” und die Angabe des richtigen privaten Key-Files voraus.

Hinweis 2:
Die Passphrase muss man sich unbedingt merken. Sie sollte hinreichend lang (deutlich länger als bei einem Passwort) sein und Sonderzeichen beinhalten. Von dieser Passphrase hängt die die Einsetzbarkeit und im Kompromittierungsfall auch die Sicherheit künftiger key-basierter SSH-Verbindungen ab. Die private Schlüssel-Datei wird mit dieser Passphrase verschlüsselt (!) im oben gewählten Verzeichnis hinterlegt. Ohne Kenntnis der Passphrase ist der Schlüssel nicht im Rahmen der SSH-Authentifizierung einsetzbar.

Kopieren des öffentlichen Schlüssels auf den Remote Server – hier den Strato-V-Server

Von einem anderen Terminalfenster loggen wir uns nun auf dem Strato-Server ein:

mysystem:~> ssh xtarjax@hxxxxxxx.stratoserver.net -p 6xxxx
xtarjax@hxxxxx:~>mkdir .ssh 
xtarjax@hxxxxx:~>cd .ssh
xtarjax@hxxxxx:~/.ssh>touch 600 
authorized_keys

Vom anderen lokalen Terminal kopieren wir nun das File mit dem öffentlichen (public) key auf den Server:

mysystem:~> scp -P 6xxxx ./.ssh/id_rsa.pub xtarjax@hxxxxx.stratoserver.net:/home/xtarjax/.ssh
Password: 
id_rsa.pub   

Man beachte das großgeschriebene “P” in der Option für die Portangabe.

Wir wechseln wieder zu unserem Terminal mit der Remote-Verbindung:

xtarjax@hxxxxx:~/.ssh>cat id_rsa.pub >> authorized_keys
xtarjax@hxxxxx:~/.ssh>cat authorized_keys
xtarjax@hxxxxx:~/.ssh>rm id_rsa.pub
xtarjax@hxxxxx:~/.ssh>exit

Test der key-basierten Authentifizierung

Nun testen wir den Login mit den asymmetrischen Keys:

mysystem:~>ssh xtarjax@hxxxxxxx.stratoserver.net -p 6xxxx 
Enter passphrase for key '/home/myself/.ssh/id_rsa': 
Last login: Mon Nov  4 17:10:34 2013 from mysystem.mydomain.de
Have a lot of fun...
xtarjax@hxxxxxxx:~> 

Bei der Rückfrage nach der Passphrase ist natürlich die Passphrase für den privaten Key anzugeben.

Hinweis:
Hat man einen von “id_rsa” abweichenden Namen bei der Generierung verwendet (oder mehrere private Key Files im Einsatz oder ein anderes verzeichnis zur Ablage gewählt) so muss man die Option “-i” verwenden:

mysystem:~>ssh xtarjax@hxxxxxxx.stratoserver.net -p 6xxxx  -i  PFAD/KEY_FILE 
Enter passphrase for key 'PFAD/KEY_FILE': 
Last login: Mon Nov  4 17:10:34 2013 from mysystem.mydomain.de
Have a lot of fun...
xtarjax@hxxxxxxx:~> 

PFAD/KEY_FILE geben dabei den Pfad zu dem zu verwendenden File mit dem privaten SSH-Key an.

Wichtig – Sicherung der Keyfiles :
Auf unserem lokalen System sichern wir die generierten Schlüssel an einem sicheren (verschlüsselten) Ort. Es ist entscheidend, dass wir den privaten Key bei Bedarf aus einer gesicherten Datei rekonstruieren können. Sonst ist später je nach Einstellung für den SSH-Dämon ggf. kein Zugang mehr zum Server möglich.

Im lokalen “~/.ssh”-Verzeichnis können wir danach den public key auch löschen. Benötigt wird die Datei für den privaten Key. Die Rechte am entsprechenden File kontrollieren wir und setzen sie bei Abweichungen ggf. auf “600”.

Änderung der SSHD-Konfiguration auf dem Server

Hat der zertifikatsbasierte SSH-Zugang zum Server einwandfrei funktioniert, können wir nun die passwortbasierte Authentifizierung in der SSH-Konfiguration des Servers abschalten. Dazu editieren bzw. ergänzen wir als root die Datei “/etc/ssh/sshd_cofig” auf dem Server bzgl. folgender Einträge :

RSAAuthentication yes
PubkeyAuthentication yes

# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
# but this is overridden so installations will only check .ssh/authorized_keys
AuthorizedKeysFile      .ssh/authorized_keys<br>
&
# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication no
#PermitEmptyPasswords no
# Change to no to disable s/key passwords
ChallengeResponseAuthentication no

UsePAM no

Hinweis:
UsePAM kann man in der oben angegebenen Konfiguration auch auf “yes”setzen. Man beachte hierzu aber die Hinweise in der Datei:

# Set this to 'yes' to enable PAM authentication, account processing, 
# and session processing. If this is enabled, PAM authentication will 
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication.  Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.

Wem das alles immer noch nicht reicht – oder wenn man seinen Usern hinsichtlich der Komplexität der selbst gewählten Passphrase für ihre Key-Dateien nicht traut – der kann zusätzlich ein Passwort setzen und dessen Eingabe verlangen. Dies geht dann mit

AuthenticationMethods publickey,password

in der sshd.conf. Siehe auch
https://access.redhat.com/site/ documentation/en-US/ Red_Hat_Enterprise_Linux/6/html/ Deployment_Guide/s2-ssh-configuration-keypairs.html

SSH unter Windows

Will man SSH von einem Windos-Client aus einsetzen, benutzt man das Opensource-Programm Putty – sowohl um Keys zu generieren als auch um die SSH-Verbindung auf dem Client zu parametrieren.

Achtung:
Ein direkter Einsatz einer ggf. auf einem Linux-Client erzeugten privaten SSH-Key-Datei – wie unsere obige “id_rsa”-Datei – ist unter PUTTY nicht möglich. Dennoch kann man die Datei verwenden: Das erfordert jedoch erst einen Import und dann ein Abspeichern in dem für PUTTY geeigneten Format. Man lese sich hierzu die ausführlichen Hilfeseiten von PUTTY durch.

ACHTUNG – Nachtrag Okt. 2016: Erheblich veränderte Sicherheitslage seit 2015

Diese kleine Artikelserie zur Einrichtung eines gehosteten Servers ist nun schon etwas älter. Wer meint, durch die obigen Maßnahmen bereits ein sicheres System zu haben, irrt deshalb. Durch die heutigen Möglichkeiten sind u.a. bestimmte Algorithmen der initialen Schlüsselbestimmung über das in SSH eingebaute Diffie-Hellman-Merkle-Verfahren nicht mehr als sicher einzustufen.

OpenSSH sollte daher unbedingt in der aktuellsten Variante 7.2p eingesetzt werden. Das entsprechende Paket findet sich im den SuSE “network”-Repository für aktuelle Opensuse Versionen (ab 13.1 bis Leap 42.2 und Tumbleweed). Siehe die Repos unter http://download.opensuse.org/ repositories/ network/

Zudem sollten auf dem Server in der “/etc/ssh/sshd_config” sowie auf den Client-Systemen in der “/etc/ssh/ssh_config” etliche weitere Einstellungen zur Härtung des SSH-Systems vorgenommen werden. Lesen Sie sich hierzu bitte den folgenden Artikel sorgfältig durch:
https://stribika.github.io/ 2015/01/04/ secure-secure-shell.html

Die meisten der dortigen Anweisungen sind einfach umzusetzen und schaden zumindest nicht, wenn man die Konfiguration der SSH-Clients unter seiner eigenen Kontrolle hat. Davon gehe ich bei gehosteten Servern aus.

Ich werde mich bemühen, an passender Stelle mal ein Update zu einer SSH-Konfiguration nachzuliefern, die aktuellen Anforderungen gerecht wird.

Links

https://help.ubuntu.com/community/ SSH/OpenSSH/Keys

http://en.wikibooks.org/wiki/OpenSSH/ Cookbook/Authentication_Keys

http://www.linuxproblem.org/ art_9.html

https://access.redhat.com/site/ documentation/ en-US/Red_Hat_Enterprise_Linux/ 6/html/ Deployment_Guide/s2-ssh-configuration-keypairs.html

http://kaotickreation.com/ 2008/05/21/ disable-ssh-password-authentication-for-added-security/

http://support.hostgator.com/ articles/ specialized-help/technical/how-to-disable-password-authentication-for-ssh

http://wiki.centos.org/HowTos/ Network/SecuringSSH

http://askubuntu.com/ questions/ 101670/ how-can-i-allow-ssh-password-authentication-from-only-certain-ip-addresses

http://superuser.com/ questions/ 303358/ why-is-ssh-key-authentication-better-than-password-authentication

http://forums.opensuse.org/ english/ get-technical-help-here/ network-internet/ 489448-sshd-password-authentication-still-working.html

https://stribika.github.io/ 2015/01/04/ secure-secure-shell.html