Wie stelle ich eine Verbindung zum FTPS-Server mit Datenverbindung her, die dieselbe TLS-Sitzung verwendet?

8

Umgebung: Ich verwende Sun Java JDK 1.8.0_60 unter 64-Bit-Windows 7 mit Spring Integration 4.1.6 (das intern scheinbar Apache Commons Net 3.3 für FTPS-Zugriff verwendet).

Ich versuche, mit unserer Anwendung einen automatischen Download vom FTP-Server unseres Kunden zu integrieren. Ich habe es erfolgreich mit SFTP-Servern mit Spring Integration ohne Probleme für andere Clients ohne Probleme gemacht, aber dies ist das erste Mal, dass ein Client uns FTPS verwendet hat, und es ist sehr verwirrend, es zu verbinden. Während ich in meiner realen Anwendung Spring Integration mit XML-Beans konfiguriere, versuche ich zu verstehen, was nicht funktioniert. Ich verwende den folgenden Testcode (obwohl ich den tatsächlichen Host / Benutzername / Passwort hier anonymisiere):

%Vor%

Ich führe diesen Code mit -Djavax.net.debug=all aus, um alle TLS-Debuginformationen auszudrucken.

Die "control" Hauptverbindung zum FTPS-Server funktioniert gut, aber wenn ich versuche, die Datenverbindung für die Liste (oder irgendeine andere Datenverbindung, die ich ausprobiert habe) zu öffnen, bekomme ich javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake , verursacht durch% Code%. Wenn ich den Schluck-Ausnahmen-Fangblock um den java.io.EOFException: SSL peer shut down incorrectly -Befehl auskommentiere, kann ich sehen (obwohl die javax.net.debug-Ausgabe), dass der Server die folgende Nachricht gesendet hat, nachdem er den Datenverbindungs-SSL-Handshake zurückgewiesen hat:

%Vor%

Was anscheinend geschieht (und dies ist mein erstes Mal, dass ich mit FTPS zu tun habe, obwohl ich mich vorher mit einfachem FTP beschäftigt habe), ist die Art, wie der Server Authentifizierung und Verschlüsselung sowohl über die Kontroll- als auch die Datenverbindungen gewährleistet Eine "normale" TLS-Verbindung zum Herstellen der Steuerverbindung und Authentifizierung findet dort statt. Jede Datenverbindung erfordert, dass sich der Client mit derselben TLS-Sitzung verbindet. Das macht für mich Sinn, wie es funktionieren soll, aber die Apache Commons Net FTPS-Implementierung scheint das nicht zu tun. Es scheint zu versuchen, eine neue TLS-Sitzung einzurichten, und daher lehnt der Server den Versuch ab.

Basierend auf der Frage zur Wiederaufnahme von SSL-Sitzungen in JSSE scheint es so zu sein, dass Java für jede Sitzung eine andere Sitzung voraussetzt oder erfordert Host / Post-Kombination. Meine Hypothese ist, dass, da die FTPS-Datenverbindung auf einem anderen Port als die Steuerverbindung ist, sie die vorhandene Sitzung nicht findet und versucht, eine neue einzurichten, so dass die Verbindung fehlschlägt.

Ich sehe drei Hauptmöglichkeiten:

  1. Der Server folgt nicht dem FTPS-Standard, da er dieselbe TLS-Sitzung am Datenport wie am Steuerport erfordert. Ich kann mit dem Server (mit dem gleichen Host / Benutzer / Passwort, wie ich versuche, in meinem Code zu verwenden) mit FileZilla 3.13.1 verbinden. Der Server identifiziert sich selbst als "FileZilla Server 0.9.53 Beta" bei der Anmeldung, also ist dies vielleicht eine Art von proprietärer FileZilla-Methode, und es gibt etwas Seltsames, was ich tun muss, um Java davon zu überzeugen, dieselbe TLS-Sitzung zu verwenden. li>
  2. Der Apache Commons Net-Client folgt nicht wirklich dem FTPS-Standard und erlaubt nur eine Teilmenge, die das Sichern der Datenverbindungen nicht erlaubt. Dies würde seltsam erscheinen, da es die Standardmethode ist, sich von Java aus mit FTPS zu verbinden.
  3. Ich vermisse etwas völlig und missdiasse das.

Ich würde mich über jede mögliche Richtung freuen, wie Sie sich mit dieser Art von FTPS-Server verbinden können. Danke.

    
Peter Cooper Jr. 04.09.2015, 13:01
quelle

3 Antworten

13

Tatsächlich erfordern einige FTP (S) -Server, dass die TLS / SSL-Sitzung für die Datenverbindung wiederverwendet wird. Dies ist eine Sicherheitsmaßnahme, mit der der Server überprüfen kann, ob die Datenverbindung von demselben Client wie die Steuerverbindung verwendet wird.

Einige Referenzen für gängige FTP-Server:

Was Ihnen bei der Implementierung helfen kann, ist, dass der Cyberduck FTP (S) -Client die Wiederverwendung von TLS / SSL-Sitzungen unterstützt und Apache Commons Net-Bibliothek verwendet:

  • Ссылка - Sitzungsschlüssel für Datenverbindung erneut verwenden

  • Siehe FTPClient.java code (erweitert Commons Net FTPSClient ), insbesondere dessen override von _prepareDataSocket_ Methode :

    %Vor%
  • Es scheint, dass die _prepareDataSocket_ -Methode speziell zu Commons Net FTPSClient hinzugefügt wurde, um die Implementierung der TLS / SSL-Sitzung wiederverwenden zu können:
    Ссылка

    Eine native Unterstützung für die Wiederverwendung steht noch aus:
    Ссылка

  • Sie müssen die Spring Integration DefaultFtpsSessionFactory.createClientInstance() natürlich überschreiben, um Ihre benutzerdefinierte FTPSClient Implementierung mit der Unterstützung für die Sitzungswiederverwendung zurückzugeben.

Die obige Lösung funktioniert seit JDK 8u161 nicht mehr.

Laut Release-Informationen zum JDK 8u161-Update (und dem Antwort von @Laurent ):

  

TLS-Sitzungshash und erweiterte Master-Secret-Erweiterung wurde hinzugefügt

     

...

     

Im Falle von Kompatibilitätsproblemen kann eine Anwendung die Aushandlung dieser Erweiterung deaktivieren, indem sie die Systemeigenschaft jdk.tls.useExtendedMasterSecret auf false im JDK

setzt

Das heißt, Sie können dies aufrufen, um das Problem zu beheben:

%Vor%

Dies sollte jedoch nur als Problemumgehung betrachtet werden. Ich kenne keine richtige Lösung.

    
Martin Prikryl 04.09.2015, 18:27
quelle
2

Damit der Vorschlag von Martin Prikryl funktioniert, musste ich den Schlüssel nicht nur unter socket.getInetAddress().getHostName() , sondern auch unter socket.getInetAddress().getHostAddress() speichern. (Lösung gestohlen von hier .)

    
NotX 25.09.2016 19:23
quelle
2

Sie können diese SSLSessionReuseFTPSClient-Klasse verwenden:

%Vor%

Und mit openJDK 1.8.0_161:

Wir müssen festlegen:

%Vor%

nach Ссылка

TLS-Sitzungshash und erweiterte Master-Secret-Erweiterung wurde hinzugefügt

Im Falle von Kompatibilitätsproblemen kann eine Anwendung die Aushandlung dieser Erweiterung deaktivieren, indem sie die Systemeigenschaft jdk.tls.useExtendedMasterSecret im JDK auf false setzt

    
Laurent Grousset 06.03.2018 14:04
quelle