Laden...

SSH.NET – Portforwarding funktioniert nicht

Erstellt von pollito vor einem Jahr Letzter Beitrag vor einem Jahr 1.003 Views
pollito Themenstarter:in
314 Beiträge seit 2010
vor einem Jahr
SSH.NET – Portforwarding funktioniert nicht

Hallo,

ich habe mehrere Anwendungen, die SSH.NET (SSH.NET) nutzen. Hierbei handelt es sich bisher immer um Datenbankzugriffe auf MySQL- bzw. MariaDB-Datenbanken. Nun muss ich eine weitere Anwendung erstellen, die ebenfalls auf eine MariaDB-Datenbank zugreift – das treibt mich aber zum Wahnsinn.

Die SSH-Verbindung wird dabei erfolgreich hergestellt und ich kann beliebige Shell-Befehle absetzen. So weit, so gut. Allerdings möchte ich auf die Datenbank zugreifen, so dass ich eine lokale Portweiterleitung einrichte – diese scheint jedoch nicht zu wirken, obwohl im Debugger alles richtig erscheint.

Nun ein wenig Code, bevor ich weiter erkläre:


			ConnectionInfo ConnNfo = new ConnectionInfo("domäne.tld", 22, "ssh-user",
				new AuthenticationMethod[]
				{
					new PrivateKeyAuthenticationMethod("ssh-user", new PrivateKeyFile[]
						{
							new PrivateKeyFile(@"C:\Daten\Visual Studio\Projects\Z-Tests\sshtest2\.ssh\private.key", "PassPhrase")
						}
					),
				}
			);

			using var sshclient = new SshClient(ConnNfo);

			sshclient.Connect();

			var portfwd = new ForwardedPortLocal(IPAddress.Loopback.ToString(), 3306, "localhost", 3306);
			sshclient.AddForwardedPort(portfwd);
			portfwd.Start();

			using MySqlConnection MySqlCon = new ("server=127.0.0.1; user id=benutzer; password=kennwort; database=datenbank; Allow Zero Datetime=True; persistsecurityinfo=False");

			/*
			 * Unbehandelte Ausnahme
			 * 
			 * MySql.Data.MySqlClient.MySqlException: "Reading from the stream has failed."
			 * 
			 * Innere Ausnahme
			 * EndOfStreamException: Attempted to read past the end of the stream.
			 * 
			 */
			MySqlCon.Open();			// <--- Ausnahme

			MySqlCon.Close();
			sshclient.Disconnect();

Im Debugger sehe ich, dass die lokale Portweiterleitung richtig eingerichtet und gestartet ist:


-	portfwd	{Renci.SshNet.ForwardedPortLocal}	Renci.SshNet.ForwardedPortLocal
		BoundHost		"127.0.0.1"		string
		BoundPort		3306			uint
		Host			"localhost"		string
		IsStarted		true			bool
		Port			3306			uint


Auch der SSH-Client ist richtig eingerichtet und ich kann u. a. Shell-Befehle wir z. B.


Console.WriteLine(sshclient.CreateCommand("ls -lah ~/.ssh").Execute());

erfolgreich ausführen.

Nun halte ich das Programm vor MySqlCon.Open() an und schaue mir die im System benutzten Ports mit


netstat -bano -p TCP

an. Dabei stelle ich folgendes fest (Ausschnitt):




Aktive Verbindungen

  Proto  Lokale Adresse         Remoteadresse          Status           PID

  TCP    10.0.70.5:59619        192.168.70.204:49172   WARTEND         0
  TCP    10.0.70.5:59620        192.168.70.204:49172   WARTEND         0
  TCP    10.0.70.5:59773        192.168.70.204:135     HERGESTELLT     5732
 [spoolsv.exe]
  TCP    10.0.70.5:59774        192.168.70.204:135     HERGESTELLT     5732
 [spoolsv.exe]
  TCP    10.0.70.5:59775        192.168.70.204:135     HERGESTELLT     5732
 [spoolsv.exe]
  TCP    10.0.70.5:59776        192.168.70.204:49172   SYN_GESENDET    5732
 [spoolsv.exe]
  TCP    10.0.70.5:59777        192.168.70.204:49172   HERGESTELLT     5732
 [spoolsv.exe]
  TCP    127.0.0.1:3306         0.0.0.0:0              ABHÖREN         42608
 [sshtest2.exe]
  TCP    127.0.0.1:8884         0.0.0.0:0              ABHÖREN         4
 Es konnten keine Besitzerinformationen abgerufen werden.
  TCP    127.0.0.1:9395         127.0.0.1:56791        HERGESTELLT     6704
 

Bei Zeile


TCP    127.0.0.1:3306         0.0.0.0:0                ABHÖREN         42608

sehe ich den Port und die PID = 42608, die mein Testprogramm sshtest2.exe bekommen hat.

Wie ist das zu deuten? Ich hätte folgendes erwartet:


TCP    127.0.0.1:3306         127.0.0.1:3306           ABHÖREN         42608

Ich verstehe das einfach nicht, denn andere Programme, die genauso arbeiten, funktionieren tadellos.

Ein Parameter unterscheidet sich: Es handelt sich um einen anderen Internet-Provider (all-inkl, Webspace-Tarif ALL-INKL Business, Webhosting Tarif ALL-INKL BUSINESS - ALL-INKL.COM). Allerdings kann ich mir beim besten Willen nicht vorstellen, dass dies etwas damit zu tun hat, da es sich um eine lokale Portweiterleitung handelt.

Kennt sich jemand von euch damit aus und kann mir weiterhelfen?

Schonmal lieben Dank und viele Grüße

René

René

D
261 Beiträge seit 2015
vor einem Jahr

Versuch es mal mit:


var portfwd = new ForwardedPortLocal("127.0.0.1", 3306, "127.0.0.1", 3306);

oder


var portfwd = new ForwardedPortLocal(IPAddress.Loopback.ToString(), 3306, "127.0.0.1", 3306);

pollito Themenstarter:in
314 Beiträge seit 2010
vor einem Jahr

Danke! Ich hatte in meiner unendlichen Verzweiflung vergessen, zu erzählen, dass ich dies schon alles durchgetestet habe.

René

pollito Themenstarter:in
314 Beiträge seit 2010
vor einem Jahr

Danke! Ich hatte in meiner unendlichen Verzweiflung vergessen, zu erzählen, dass ich dies schon alles durchgetestet habe.

Mittlerweile habe ich auch die Verbindungszeichenkette so angepasst, dass ich für meine Tests "nur" an der Methode ForwardedPortLocal drehen muss.


			var portfwd = new ForwardedPortLocal("127.0.0.1", 3306, "127.0.0.1", 3306);
			sshclient.AddForwardedPort(portfwd);
			portfwd.Start();
			using MySqlConnection MySqlCon = new($"server={portfwd.BoundHost}; port={portfwd.BoundPort}; user id=...");

Ich habe mich auch zu Tode gegoogelt, wobei ich nicht alleine zu sein scheine. Allerdings keiner der Tipps konnte weiterhelfen. Daher habe ich das direkt auf GitHub unter Local port forwarding "ForwardedPortLocal" does not work · Issue #1066 · sshnet/SSH.NET beschrieben. Bisher aber kein Feedback, leider.

Das Ausführen auf anderen Rechnern bzw. sogar mit Admin-Rechten brachte nichts. Nun gehen mir die Ideen aus.

René

16.827 Beiträge seit 2008
vor einem Jahr

Daher habe ich das direkt auf GitHub unter
>
beschrieben. Bisher aber kein Feedback, leider.

Du hast nicht wirklich erwartet, dass Du binnen einer Stunde eine Antwort bekommst, oder...?
Realistisch: Tage, wenn nicht mehr.


new ForwardedPortLocal("127.0.0.1", 3306, "127.0.0.1", 3306);

Die Wahrscheinlichkeit, dass Du Inbound und Outbound exakt den gleichen Port auf dem gleichen Host verwenden kannst, ist unter 0.
So funktioniert leider Networking nicht.

pollito Themenstarter:in
314 Beiträge seit 2010
vor einem Jahr

Doch, so funktioniert SSH.NET. Nachdem man eine SSH-Verbindung hergestellt hat, kann man die Portweiterleitung einrichten. Die Methode


new ForwardedPortLocal("127.0.0.1", 3306, "127.0.0.1", 3306);

leistet das:


-	portfwd	{Renci.SshNet.ForwardedPortLocal}	Renci.SshNet.ForwardedPortLocal
		BoundHost		"127.0.0.1"		string
		BoundPort		3306			uint
		Host			"127.0.0.1t"	string
		IsStarted		true			bool
		Port			3306			uint

ForwardedPortLocal.BoundHost und ForwardedPortLocal.BoundPort stellen die Quelle dar während ForwardedPortLocal.Host und ForwardedPortLocal.Port das Ziel – es ist durchaus möglich und in den meisten Fällen sogar die Regel, dass Quelle und Ziel (visuell) gleich sind.

René

pollito Themenstarter:in
314 Beiträge seit 2010
vor einem Jahr

UPDATE++++

Ich habe das gleiche Testprogramm aber mit anderen Verbindungs- und Zugangsdaten ausgeführt. Im Wesentlichen handelt es sich um andere Internet-Provider. Hier stelle ich fest, dass die anderen Provider keine Probleme machen und alles läuft, wie es sein sollte. Dabei ist mir etwas aufgefallen: Den Fehler macht nicht die Methode ForwardedPortLocal, wie ich fälschlicherweise vermutete. Wenn ich nach der Portweiterleitung anhalte, sehe ich in allen Fällen folgendes:


TCP    127.0.0.1:3306         0.0.0.0:0                ABHÖREN         42608

Also das ist korrekt und ich hatte mich geirrt.

Nun habe ich bei den fehlerfreien Programmläufen direkt nach MySqlConnection.Open angehalten und siehe da, folgendes Bild bot sich mir an:


Proto    Lokale Adresse         Remoteadresse          Status           PID

  TCP    127.0.0.1:3306         0.0.0.0:0              ABHÖREN         51156
 [sshtest2.exe]
  TCP    127.0.0.1:3306         127.0.0.1:62024        HERGESTELLT     51156
 [sshtest2.exe]
  TCP    127.0.0.1:62024        127.0.0.1:3306         HERGESTELLT     51156
 [sshtest2.exe]

Hier sieht man, dass zwei Verbindungen hergestellt sind und dass der Port 62024 als "Zwischenport" verwendet wird.

Nun glaube ich langsam, dass der Provider (all-inkl) in die Suppe spuckt und das Aushandeln des "Zwischenports" unterbindet.

Ich werde daher ein Ticket bei denen eröffnen, um sicher zu sein, dass die es unterbinden.

René

16.827 Beiträge seit 2008
vor einem Jahr

Die Wahrscheinlichkeit, dass Du Inbound und Outbound exakt den gleichen Port auf dem gleichen Host verwenden kannst, ist unter 0.

Doch, so funktioniert SSH.NET.

Das kann auch SSH.NET nicht, denn es ist eine Einschränkung des Betriebssystems, dass für Inbound und Outbound auf der gleichen Maschine nicht der selbe Port verwendet werden kann.
Aus Deinem Update wird klar: SSH.NET wendet (intern wohl) einen Trick an, erzeugt zwei Bindings, nicht nur eines. War mir nicht klar; Beschreibung bleibt dennoch korrekt.

pollito Themenstarter:in
314 Beiträge seit 2010
vor einem Jahr

Zunächst sorry, dass ich etwas abschweife, aber ich denke, das kann für den einen oder anderen interessant sein.

Ich habe weiter geforscht und bin zur Erkenntnis gekommen, dass mein Provider all-inkl den Zugriff auf Datenbanken über einen SSH-Tunnel unterbindet. Zwar ist SSH möglich, nicht jedoch einen SSH-Tunnel einzurichten. Daher habe ich den Support kontaktiert, der – wie immer – sehr schnell antwortete:

vielen Dank für Ihre Anfrage.

Der Zugriff auf die Datenbanken über einen SSH-Tunnel ist bei uns nicht möglich. Über eine VPN-Verbindung ist dennoch ein verschlüsselter Transfer möglich. Auf unserer Website finden Sie folgenden Link zur Einrichtung:


>

Allerdings kommt bei uns VPN nicht in Frage, denn die Software soll leicht zu deployen sein, ohne einen OpenVPN-Client installieren zu müssen, der auch programmgesteuert überwacht und ferngesteuert werden müsste.

Daraufhin habe ich gefragt, warum kein SSH-Tunnel möglich ist und ob dies zumindest in Managed-Servern (auch das haben wir bei denen) gehen würde. Schließlich haben andere Provider dieses Feature im Portfolio – sie werben sogar damit und stellen Anleitungen zur Verfügung. Dazu gehören IONOS, Mittwald, Hosteurope und weitere. All-inkl meint dazu:

Der SSH Tunnel ist bei uns vor Jahren aus Sicherheitsgründen abgeschafft worden.


>

Auch auf einem Managed-Server können wir dies leider nicht freischalten.

Das hat mich nachdenklich gemacht. Wir verwenden nämlich SSH ausschließlich mit Zertifikaten, welche zusätzlich durch eine sehr starke Passphrase gesichert sind. D. h. auch wenn ein Zertifikat (der private Schlüssel) gestohlen wird, kann man ohne Passphrase nichts damit anfangen. Dagegen ist bei deren VPN-Lösung das Zertifikat nicht gesichert, so dass es beim Entwenden sofort missbraucht werden kann. Für mich ein sehr großes Fragezeichen.

Nun habe ich all-inkl gefragt, ob sie irgendwann neben PHP, Phyton und Perl, auch .NET anbieten würden. Dann könnte ich meine Anwendung auf ASP.NET umschreiben. Die Antwort war kurz und prägnant:

Die Implementierung von .NET ist derzeit bei uns nicht geplant.

Wir sind seit sehr vielen Jahren Kunde bei all-inkl und schätzen deren schnellen Support und Robustheit deren Produkte. Allerdings scheint es mir an dieser Stelle ein wenig zu viel des Guten zu sein. Schließlich dreht sich die Welt weiter und man muss einigermaßen mit der Zeit gehen.

Kennt jemand von euch Provider/Tarife auf Linux-Basis (kein Root-Server), bei denen SSH-Tunneling möglich ist und auch .NET unterstützt wird?

Ansonsten werden wir auf einen vorhandenen Root-Server ausweichen, den wir bei einem anderen Provider mieten, um uns schnell aus der Affaire zu ziehen.

Vielen Dank für eure Hilfe!

René

René

16.827 Beiträge seit 2008
vor einem Jahr

Der SSH Tunnel ist bei uns vor Jahren aus Sicherheitsgründen abgeschafft worden.

Unrecht haben sie nicht; VPN ist prinzipiell sicherer als der manuelle SSH Tunnel - für Deinen Zweck aber wohl kein Ersatz.

Die Implementierung von .NET ist derzeit bei uns nicht geplant.

Weil Du nach Providern fragst der reine Hinweis: auf Azure löst man das einfach mit Managed Identities und vNETs:

  • Privates Netz
  • Keinerlei Credentials oder Zertifikate, die man verlieren kann
  • Zugriff gesichert über Plattform-Features auf Tenant-Ebene

Managed Identities (bzw. die technische Implementierung dahinter) ist die absolut sicherste Branchenlösung, die es derzeit gibt.
Auf AWS nennt sich die Implementierung AWS Identity Service bzw IAM.

Die Vermutung, dass Du All Inkl nutzt lässt mich aber dazu schließen, dass AWS und Azure Dir zu teuer sein werden (weil Du deren Mehrleistung (und Mehr-Sicherheit?) wohl nicht benötigst).

auch wenn ein Zertifikat (der private Schlüssel) gestohlen wird, kann man ohne Passphrase nichts damit anfangen.

Weil das ist und bleibt immer der Angriffsvektor.

pollito Themenstarter:in
314 Beiträge seit 2010
vor einem Jahr

Die Vermutung, dass Du All Inkl nutzt lässt mich aber dazu schließen, dass AWS und Azure Dir zu teuer sein werden (weil Du deren Mehrleistung (und Mehr-Sicherheit?) wohl nicht benötigst).

Bisher haben wir uns über Azure und AWS keinen Kopf gemacht. Für die hier angesprochene Anwendung wäre das auch Overkill, denn es handelt sich um eine einfache Datenbankanwendung, welche Daten nur temporär verwaltet. Diese sind weder ein Betriebsgeheimnis, noch werden persönliche und/oder wichtige Daten verwaltet. Dennoch ein sehr interessantes Thema – danke fürs Ansprechen.

auch wenn ein Zertifikat (der private Schlüssel) gestohlen wird, kann man ohne Passphrase nichts damit anfangen.
Weil das ist und bleibt immer der Angriffsvektor.

Richtig, aber die All-inkl-VPN-Lösung ist, so wie sie ausgeliefert wird, noch anfälliger als die von uns verwendete SSH-Lösung: Konfigurationsdatei und Zertifikat klauen und ich bin drin.

Nochmals Danke und frohe Weihnachten!

René

René