Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Lesedauer 6 Min.

SSH für.NET-Applikationen mit SSH.NET

SSH – dahinter verbirgt sich die Abkürzung Secure Shell – ist insbesondere im Bereich der unixoiden Systeme weit verbreitet. Mit SSH.NET steht ein NuGet-Paket zur Verfügung, das die Interaktion mit der sicheren Remote Shell aus .NET-Applikationen heraus zu ermöglichen sucht.
© EMGenie

Die Secure Shell hat sich in vielen Bereichen als unersetzbares Werkzeug etabliert. Unabhängig davon, ob ein im Headless-Betrieb arbeitender Prozessrechner oder eine „unixoide Workstation“ zum Einsatz kommt: Immer dann, wenn der Zugriff unter Verbrauch von wenig Bandbreite zu erfolgen hat, führt an SSH kein Weg vorbei.

Anders als beim absoluten Klassiker Telnet gilt, dass die über die Leitung gesendeten Informationen unter Verwendung vergleichsweise starker Kryptografie abgesichert werden.

In diesem Kurz-Tutorial wollen wir das Paket SSH.NET verwenden. Als Gegenstelle dient ein mit einer aktuellen Version von Raspberry Pi OS ausgestatteter Raspberry Pi. Zu beachten ist, dass die Prozessrechner mit den Standardeinstellungen aus Sicherheitsgründen kein SSH-Interface mehr exponieren. Anleitungen zur Aktivierung findet man als interessierter Experimentator unter dem Stichwort Remote Access in der Raspberry-Pi-Dokumentation.

Einrichtung von Projektstruktur und Bibliothek

Einer der wichtigsten Erfolgsfaktoren von NuGet ist die Einfachheit der Installation selbst bei komplexesten Komponenten. Was einst manuelles Herumklicken mit Assembly und Co. erforderte, können .NET-Entwicklerinnen und -Entwickler nur mit wenigen Klicks innerhalb von Visual Studio erledigen. In den folgenden Schritten wollen wir mit einem auf der Vorlage Konsolen-App basierenden Projekt beginnen, als Name sei SSHTest1 angenommen.

Im Bereich der von den verschiedenen Bibliotheken unterstützten .NET-Versionen gibt es keinen wirklich einheitlichen Standard. Neben der Konsultation der Dokumentation kann es auch empfehlenswert sein, die offizielle NuGet-Galerie zu besuchen. Im Fall von SSH.NET informiert sie wie in Bild 1 gezeigt über die unterstützten Versionen.

Nun ist klar: Unser Konsolenprojekt muss auf .NET 8.0 basieren (Bild 1)

Nun ist klar: Unser Konsolenprojekt muss auf .NET 8.0 basieren (Bild 1)

 

© NuGet.org

Zum Abschluss der Vorbereitungshandlungen bietet es sich an, einen ersten Testlauf gegen den Raspberry Pi durchzuführen. Hierzu ist folgender Code erforderlich:

using Renci.SshNet;

using (var client = new SshClient("192.168.1.103", "pi", "raspberry")) {
  client.Connect();
  using SshCommand cmd = client.RunCommand("echo 'Greets from RPi!'");
  Console.WriteLine(cmd.Result);
}
 

Die Verwendung der Bibliothek erfolgt im Allgemeinen durch Nutzung eines SshClient-Objekts, das die Beziehung zwischen der .NET-Applikation und der unixoiden Gegenstelle repräsentiert. Wir authentifizieren uns hier unter Nutzung von Benutzernamen und Passwort – wer sich stattdessen mit einem Dateipaar ausweisen möchte, muss eine andere Variante des Objekt-Konstruktors verwenden.

Der Rest des Codes nutzt dann den Befehl RunCommand, um einen Befehl auf dem unixoiden Prozessrechner zur Ausführung zu bringen. Zu guter Letzt wird die Antwort in die Kommandozeile der Windows-Workstations ausgeworfen – die Ausführung des Programms führt zum Erscheinen der Begrüßungsmeldung.

Interaktive Experimente mit SSH.NET

In der Praxis sind „direkt und uninteraktiv“ ablaufende Kommandos höchst selten – das geringste Ärgernis, das man sich einhandelt, sind erhebliche Latenzen. Im nächsten Schritt wollen wir den für Prozessrechnerjobs hilfreichen Scanner nmap in Betrieb nehmen. Im Interesse der didaktischen Komplexität wird der Autor davon ausgehen, dass das Image des Raspberry Pi das Produkt noch nicht enthält – wäre das Paket bereits vorhanden, würden die folgenden Experimente weniger lehrreich ausfallen.

Als ersten Versuch bietet es sich jedenfalls an, nach folgendem Schema die Ausführung der Engine zu befehligen. Beachten Sie außerdem, dass die Auswertung nun sowohl das Feld Error als auch das Feld Result tangiert:

 

using SshCommand cmd = client.RunCommand("nmap -sN 192.168.1.0/24");
Console.WriteLine(cmd.Result + " / " +  cmd.Error);

 

Als Ergebnis gibt die Ausführung den folgenden String zurück:

 

bash: line 1: nmap: command not found.

 

Würde unser Code das Error-Feld nicht auswerten, so erschiene ein leeres Kommandozeilenfenster am Bildschirm.

Aus der Logik folgt, dass der nächste Schritt das probeweise Nachinstallieren des Pakets ist. Unter unixoiden Betriebssystemen ist die Paketverwaltung einfach, weshalb eine naive Modifikation folgendermaßen aussehen würde:

 

using SshCommand cmd = client.RunCommand("sudo apt-get install nmap");

 

Als Resultat erscheint ein „leeres“ Kommandozeilenfenster, das auch nach einiger Zeit nicht vom Feld am Bildschirm verschwindet. Ursache dieses unbefriedigenden Verhaltens ist, dass der Befehl apt-get install vom Benutzer eine Eingabe verlangt. Spezifischerweise präsentiert sich der Flow wie in Bild 2 gezeigt.

Das Programm hängt beim Statement Do you want to continue? [Y/n] (Bild 2)

Das Programm hängt beim Statement Do you want to continue? [Y/n] (Bild 2)

© Autor

Die nächste Version des Programms präsentiert sich folgendermaßen:

 

using (var client = new SshClient("192.168.1.103", "pi", "raspberry"))
{
  client.Connect();
  using (ShellStream shellStream = client.CreateShellStream("ShellName", 80, 24, 800, 600, 1024))
  {
    string prompt = shellStream.Expect(new Regex(@"[$>]"));

 

Anstatt wie bisher unter Nutzung von RunCommand direkt Befehle gegen den Prozessrechner zur Ausführung zu bringen, setzen wir nun auf einen ShellStream. Dabei handelt es sich um eine Art des IO-Streams, der allerdings mit der angeschlossenen SSH-Gegenstelle zu interagieren sucht.

Shells sind für die Abarbeitung von per Batch ablaufender Aufgaben vorgesehen. Da der Prozessrechner für die Bereitstellung der Shell-Session mitunter etwas Zeit in Anspruch nimmt, sorgt die Zeile mit dem Regex @"[$>]" für eine variable Totzeit. Spezifischerweise gilt, dass der ShellStream so lange anhält, bis eine den Regex „befriedigende“ Antwort eintrifft. Da wir hier auf den Systemprompt matchen, deutet dies auf das Verfügbarsein des Prozessrechners hin.

Die eigentliche Installationsanweisung nutzt dann einen weiteren Matcher-Block, um auf das Erscheinen der Abfrage zu warten. Die Wartezeit ist erforderlich, weil die Berechnung der notwendigen Paket-Transaktionen insbesondere auf langsameren Prozessrechnern einige Zeit in Anspruch nehmen kann:

 

  shellStream.WriteLine("sudo apt-get install nmap");    
  prompt = shellStream.Expect("Do you want to");    
  Thread.Sleep(100);    
  shellStream.WriteLine("y");    
  shellStream.Expect(new Regex(@"[$>]"));  
}

 

Die Zeile shellStream.WriteLine("y"); kümmert sich dann um das Senden der Quittierung; ein weiterer Regex wartet die erfolgreiche Abarbeitung der (lange dauernden) Paket-Operationen des Betriebssystems ab.

Nach der erfolgreichen Abarbeitung des Installationsprozesses zerstören wir das ShellStream-Objekt, um danach nach dem bekannten Schema einen Scanbefehl loszutreten:

 

  using SshCommand cmd = client.RunCommand("nmap -sN 192.168.1.0/24");  
  Console.WriteLine(cmd.Result + " / " + cmd.Error);
}

 

Ergebnis der Programmausführung ist nur das Erscheinen der in Bild 3 gezeigten Fehlermeldung: Ursache dafür ist, dass manche fortgeschrittene Scanarten Superuserrechte voraussetzen, unser Programm allerdings mit den Rechten des Pi-Users arbeitet.

Der Start von nmap verlief (prinzipiell) erfolgreich (Bild 3)
Der Start von nmap verlief (prinzipiell) erfolgreich (Bild 3) © Autor

Der Gutteil der Ausführungszeit – bis zum Erscheinen der Meldung kann etwas Zeit ins Land gehen – wird für die Operationen des Paketmanagers verbraucht. Dies lässt sich dadurch überprüfen, dass man beispielsweise unter Nutzung von Putty eine zweite Verbindung zum Prozessrechner aufbaut und dort eine beliebige Paketmanager-Operation ausführt. Dies scheitert – wie in Bild 4 gezeigt – mit einem Verweis darauf, dass das Paketmanager-Singleton gesetzt ist und deshalb keine weiteren Paketoperationen durchgeführt werden können.

Die Fehlermeldung vermeldet paradoxerweise Erfolg (Bild 4)

Die Fehlermeldung vermeldet paradoxerweise Erfolg (Bild 4)

© Autor

Fazit und Ausblick

Obwohl wir hier nur einen winzigen Teil der Möglichkeiten der SSH.NET-Bibliothek tangiert haben, ist offensichtlich, dass sie die verschiedensten Arten der Kommunikation zwischen .NET-Applikation und Prozessrechnersystem ermöglicht.

Angemerkt sei, dass es sich hierbei nur um eine von vielen im NuGet-Ökosystem lebenden Bibliotheken handelt. In Folgeartikeln stellen wir weitere nützliche Module vor – bleiben Sie dran, denn das Selbstimplementieren von kostenlos Vorhandenem ist immer die ineffizienteste Vorgehensweise.

Neueste Beiträge

Delphi als Turbo für die mobile Entwicklung - Mobile Apps entwickeln mit Delphi, Teil 1
Delphi ermöglicht es, effizient plattformübergreifende Anwendungen zu erstellen. In diesem ersten Teil der Serie beleuchten wir die Motivation ebenso wie das Setup eines ersten Beispielprojekts.
6 Minuten
Ein Jahr CODELUTION Zertifizierungssystem – ein neuer Standard in der IT-Weiterbildung - [sponsered]
Das rollenbasierte Zertifizierungssystem für Entwickler-Schulungen der Karlsruher CODELUTION GmbH hebt sich bewusst von technologiegebundenen Zertifikaten ab.
3 Minuten
25. Sep 2025
DDC hakt nach: Wie baust Du eine Softwarearchitektur ohne Schuldenfalle auf?
Moderne Softwarearchitektur muss zukunftsfähig sein – aber auch schon heute funktionieren. David Tielke über den architektonischen Spagat zwischen Cloud, KI, Schuldenmanagement und gesundem Menschenverstand.
7 Minuten
22. Sep 2025

Das könnte Dich auch interessieren

Vertrauen ist gut – Kontrolle ist Pflicht: Christian Wenz über moderne Softwaresicherheit - Interview
Sicherheitsexperte Christian Wenz über blinden Framework-Glauben, gefährliches Vertrauen und warum echte Softwaresicherheit kein Nice-to-have ist.
4 Minuten
30. Jul 2025
JavaScript-Scanner für moderne Webanwendungen - Crashtest Security
Der JavaScript-Scanner für moderne Webanwendungen identifiziert Angriffsvektoren autmaitsch im Frontend, im Backend und in der Kommunikation zwischen beiden. Der Scan benötigt dafür nur die Domain, um den Scan zu starten.
3 Minuten
Studie: DSGVO birgt Nachteile für kleine Unternehmen - EU-Datenschutz-Grundverordnung
Laut aktueller Umfrage der TeamDrive Systems GmbH „Datensicherheit in der Cloud“ bremsen horrende Strafsummen und strikte Richtlinien die Entwicklung deutscher Unternehmen aus.
3 Minuten
11. Dez 2017
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige