FTP - Der unsterbliche Leiche
« | 27 Mar 2019 | »Als mir im Jahr 2000 mein “erster” fester Internetprovider eine Warnung wegen der Verletzung der Nutzungsbestimmungen zusandte, war der Grund ein FTP Server.
Denn im Vertrag stand tatsächlich, dass der Zugang nur für TCP Clientdienste bestimmt war und das Hochfahren eines beliebigen Servers wie HTTP oder FTP war zwar technisch möglich, doch der Provider überwachte die eingehenden Transmissionen und ermahnte seine Kunden daraufhin.
Das war dann eigentlich schon der erste und letzte Moment, wo ich einen FTP Server zu Hause in Betrieb hatte …
Anders sah es allerdings im Internet aus. Denn der Wechsel von FTP zu HTTP und anderen Dateiserver-Diensten wurde erst langsam zwischen 2000 bis 2010 vollzogen. Und auch heute ist dieses schreckliche Uraltprotokoll nicht tot zu kriegen.
Das ursprüngliche FTP ist deshalb so unglaublich umständlich, weil in der Zeit seiner Entwicklung zwei Kriterien galten:
- Jeder vertraut jedem blind
- Jeder hängt direkt mit einer fixen IP am Internet
Und deshalb kamen die Macher auf die Idee, dass neue eingehende Verbindungen des TCP Server-Sockets nur für Kontrollnachrichten zuständig sind. Man kann sich also mit Benutzernamen und Passwort anmelden, sich Verzeichnisinhalte ansehen und Downloads und Uploads vorbereiten.
Doch für den eigentlich Download bzw. Upload wird eine weitere Verbindungen auf einem anderen Port aufgebaut und darüber fließen die Bits des Inhalts.
Das schlimmste daran ist, dass neben dem Problem des Betriebs von mehreren
Ports auch noch das Server-Client Prinzip umgedreht wird. Denn für den
Verbindungsaufbau ist der “Konsument” der Client und der “Bereitsteller” der
Server, so wie man es erwartet.
Doch beim Download muss der “Konsument” einen dynamischen TCP-Server hochfahren
und der “Bereitsteller” verbindet sich als Client zu diesem um ihm seine
Daten zu senden.
Das ist ein Alptraum für Administratoren, die
Firewalls warten müssen, denn statt
einem einzigen Serverport müssen nun ganze Port-Bereiche freigegeben werden,
die zufällig mal benutzt werden und dann wieder nicht.
Und nachdem der Client ebenso als Server funktioniert, muss auch seine Firewall
das Öffnen eines Portbereiches unterstützen.
Diesem zweiten Punkt wurde mit Passiven FTP entgegengearbeitet, bei dem nur der FTP-Server mehrere TCP-Server betreibt und der Client auch immer nur Client-Verbindungen initiiert anstatt selbst zum TCP-Server zu werden.
Nicht zu vergessen sei, dass der FTP-Server immer seine öffentliche
Internetadresse kennen muss, denn im Protokoll muss der Gegenseite mitgeteilt
werden, auf welchen anderen Port auf welcher IP sie sich für Up- und Downloads
verbinden soll.
Und ist die interne IP des Servers nicht gleich der externen, dann muss dies
von Hand im Server konfiguriert sein. Besonders dumm ist, wenn sich die
öffentliche IP (z.B. durch Einwahlnetze) ändert.
Wie auch immer, viele Daten wie Treiber oder Betriebssystem-Images liegen
auch heute immer noch auf FTP Servern. Und auch bei IT-Lösungen für Kunden,
wo man Daten austauschen muss, wird schnell ein FTP-Server bereitgestellt,
weil dieser “schnell” aufgesetzt ist und Clients weit verbreitet sind.
Natürlich geht das schnell, denn wegen fehlender Sicherheitsfunktionen reicht
es einfach einen Account anzulegen und ihm ein Verzeichnis zuzuordnen.
Dann schaltet man noch die Firewall für den FTP-Port 21 und die
Übertragungs-Port-Range ab (z.B.: Ports 13000 bis 14000, tausend gleichzeitige
Verbindungen sind mehr als ausreichend für kleine Projekte), und man ist
fertig.
In der Programmierung nutzte ich ganz analog zu HTTP immer WinINET unter Windows und die libCURL unter Linux bzw. POSIX Systemen um FTP Clients zu implementieren.
WinINET
WinINET stellt uns neben seinen generischen Funktionen für alle Protokolle einige FTP-spezifische zur Verfügung, wie z.B.: FtpFindFirstFile um Dateien aufzulisten oder FtpCreateDirectory um Unterverzeichnisse anzulegen. Ansonsten funktioniert der Nutzung genau so wie für HTTP.
libCURL
Bei der libCURL ist das leider nicht so, dass es für Verzeichnisoperationen eigene APIs gibt, womit nur Up- und Downloads von im Vorhinein bekannten Pfaden “leicht” zu implementieren sind. Das Lesen eines Verzeichnisses führt zu einem Text-Stream, der geparst werden muss und das ist kein Zuckerschlecken, da jeder FTP-Server seinen eigenen Ausgabestandard wählt. Sie sind zwar ähnlich zueinander, aber eben nicht identisch.
CURL lässt uns aber native Kommandos für das Protokoll injizieren und so können
wir das Kommando MLST
für standardisierte Verzeichniseinträge nutzen,
oder MKD
um Unterverzeichnisse anzulegen.
Aber Vorsicht! Ich musste einst lange mit einer Implementierung kämpfen, da es FTP-Server gibt, die keine absoluten Pfade verkraften. Die libCURL wechselt daher immer (im Hintergrund) in das angenommene Zielverzeichnis und dort muss dann der relative Pfad und nicht der absolute genutzt werden, weil sich der Server ansonsten den übergebenen absoluten Pfad an seinen aktuelles “Working-Directory” anhängt und das Ergebnis dann ein ganz anderes (nicht existierendes= Verzeichnis ist.
Fazit
FTP ist wegen seiner Unsicherheit und Server-Client-Port-Murxerei und dann noch wegen seiner unterschiedlichen Implementierungen ein einziger Graus. Wer Dateien sicher übertragen will, sollte SFTP von SSH benutzen, oder per VPN einen sicheren Tunnel nutzen um dann per SMB fortzufahren.
Eigentlich könnte HTTP das alte FTP vollkommen ablösen, denn mit der WebDAV Erweiterung existiert für HTTP ein Standard um ebenso Verzeichnisse maschinell auszulesen und somit ein Dateisystem abzubilden (was im klassischen HTTP leider fehlt).
Doch … wie wir wissen, bleiben solche Altlasten auf unbestimmte Zeit aktiv, und so werde ich wohl noch meine letzten Atemzüge vor Programmen wie FileZilla verbringen, über welche ich meinen letzten Blog-Post per FTP zum Webserver übertrage.