当前位置: 首页 > 知识库问答 >
问题:

javax.net.ssl.SSLHandshakeExc0019:远程主机在握手过程中关闭连接FTPS

訾安邦
2023-03-14

我试图连接到需要显式FTP在TLS的FTP。我正试图从我的本地机器上做这件事。

下面是我使用的代码

FTPSClient ftpClient = new FTPSClient(false);
      ftpClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));
      ftpClient.setAuthValue("TLS");
      ftpClient.connect(host, port);
      int reply = ftpClient.getReplyCode();
      if (FTPReply.isPositiveCompletion(reply)) {

        if (ftpClient.login(username, password)) {

          ftpClient.execPBSZ(0);
          ftpClient.execPROT("P");
          ftpClient.enterLocalPassiveMode();

      InputStream is = new FileInputStream(localFilename);
      if (ftpClient.storeFile(remoteFilename, is)) {
        is.close();
      } else {
        System.out.println("Could not store file");
      }
      ftpClient.logout();

        } else {
          System.out.println("FTP login failed");
        }

        // Disconnect
        ftpClient.disconnect();

      } else {
        System.out.println("FTP connect to host failed");
      }

当我跑的时候,我得到下面的异常

    Could not connect to server.
javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
    at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
    at org.apache.commons.net.ftp.FTPSClient.sslNegotiation(FTPSClient.java:240)
    at org.apache.commons.net.ftp.FTPSClient._connectAction_(FTPSClient.java:171)
    at org.apache.commons.net.SocketClient.connect(SocketClient.java:178)
    at TestFTP.main(TestFTP.java:64)
Caused by: java.io.EOFException: SSL peer shut down incorrectly
    at sun.security.ssl.InputRecord.read(Unknown Source)
    ... 8 more

下面是我从Java CommandListener获得的日志

220-FileZilla Server 0.9.60 beta
220-written by Tim Kosse (tim.kosse@filezilla-project.org)
220 Please visit https://filezilla-project.org/
AUTH TLS
234 Using authentication type TLS
FTP client received network error javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake

下面是我尝试使用FileZilla连接时的日志。它连接良好,我可以传输文件。但是当我尝试使用Java时,它没有连接

Response:   220-FileZilla Server 0.9.60 beta
Response:   220-written by Tim Kosse (tim.kosse@filezilla-project.org)
Response:   220 Please visit https://filezilla-project.org/
Command:    AUTH TLS
Response:   234 Using authentication type TLS
Status: Initializing TLS...
Status: Verifying certificate...
Command:    USER 
Status: TLS/SSL connection established.
Response:   331 Password required
Command:    PASS xxxx
Response:   230 Logged on
Command:    PBSZ 0
Response:   200 PBSZ=0
Command:    PROT P
Response:   200 Protection level set to P
Status: Connected
Status: Retrieving directory listing...
Command:    PWD
Response:   257 "/" is current directory.
Command:    TYPE I
Response:   200 Type set to I
Command:    PASV
Response:   227 Entering Passive Mode ()
Command:    MLSD
Response:   150 Opening data channel for directory listing of "/"
Response:   226 Successfully transferred "/"
Status: Directory listing successful
Status: Retrieving directory listing...
Command:    PASV
Response:   227 Entering Passive Mode ()
Command:    MLSD
Response:   150 Opening data channel for directory listing of "/"
Response:   226 Successfully transferred "/"
Status: Directory listing successful

你们能帮忙吗?

亲切的问候乔恩

共有3个答案

缑泓
2023-03-14

我使用Cyberduck库解决了这个问题。https://github.com/iterate-ch/cyberduck
首先,为什么会出现这种握手问题,因为某些先进的FTP服务器只允许一个会话进行连接和数据传输。

1) 控制会话-

那么如何解决这个呢?

步骤1-:

首先,您需要从GitHub签出cyberduck回购协议。从这里开始-:https://github.com/iterate-ch/cyberduck

第2步-:您将看到FTP和核心模块在签出回购ftp和核心模块

步骤3-:将此模块转换为maven并为其创建jar。

步骤4-:将这个jar添加到您的项目中,但是这个jar还需要其他依赖项,因此也相应地将这些依赖项添加到项目构建路径中。

步骤5-:代码片段。

public class TestFTPS {
    public static void main(String[] args) throws SocketException, IOException {
        TrustManager[] trustManagers = new TrustManager[] { new X509TrustManager() {
            @Override
            public X509Certificate[] getAcceptedIssuers() {
                // TODO Auto-generated method stub
                return null;
            }
            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                // TODO Auto-generated method stub
            }

            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                // TODO Auto-generated method stub
            }
        } };
        SSLContext sslContext = null;
        try {
            sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustManagers, new SecureRandom());
        } catch (Exception e) {
            e.printStackTrace();
        }
        SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
        Protocol protocol = new FTPTLSProtocol();
        FTPClient client = new FTPClient(protocol, sslSocketFactory, sslContext);
        client.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));
        client.connect(ftphostname, port);
        client.execAUTH("TLS"); //SSL
        System.out.println(client.getReplyCode());
        if (client.login(username, password)) {
            client.execPBSZ(0);
            client.execPROT("P");
            String date = "Testing Data Send to provide FTP location";
            client.setFileType(FTP.BINARY_FILE_TYPE);
            client.enterLocalPassiveMode();
            InputStream is = new ByteArrayInputStream(date.getBytes());
            client.storeFile("test.txt", is);
            System.out.print(client.getReplyCode());
        }
    }
}

步骤6-:运行此代码后,您的文件将成功传输到ftp位置。

注意-:请在您的项目中添加所需的jar

希望这对你有帮助。

万俟棋
2023-03-14

该解决方案简单,技术上有点棘手,因为假设SSL会话(在其中打开连接)也应用于数据,但在FTPS的情况下,库会尝试会话外尝试数据,处理此操作的方法未在FTPS类中定义。因此,解决方案是简单地扩展FTPS类并为该方法提供实现。

这里有一个例子

public class ModifiedFTPSClient extends FTPSClient {

public ModifiedFTPSClient() {
    super("TLS", false);
}

public ModifiedFTPSClient(boolean isImplicit) {
    super("TLS", isImplicit);
}

@Override
protected void _prepareDataSocket_(final Socket socket) throws IOException {
    if (socket instanceof SSLSocket) {
        final SSLSession session = ((SSLSocket) _socket_).getSession();
        if (session.isValid()) {
            final SSLSessionContext context = session.getSessionContext();
            try {
                final Field sessionHostPortCache = context.getClass().getDeclaredField("sessionHostPortCache");
                sessionHostPortCache.setAccessible(true);
                final Object cache = sessionHostPortCache.get(context);
                final Method method = cache.getClass().getDeclaredMethod("put", Object.class, Object.class);
                method.setAccessible(true);
                method.invoke(cache, String
                        .format("%s:%s", socket.getInetAddress().getHostName(), String.valueOf(socket.getPort()))
                        .toLowerCase(Locale.ROOT), session);
                method.invoke(cache, String
                        .format("%s:%s", socket.getInetAddress().getHostAddress(), String.valueOf(socket.getPort()))
                        .toLowerCase(Locale.ROOT), session);
            } catch (NoSuchFieldException e) {
                throw new IOException(e);
            } catch (Exception e) {
                throw new IOException(e);
            }
        } else {
            throw new IOException("Invalid SSL Session");
        }
    }
}}

现在,如果我尝试使用扩展类,它将在同一个会话中运行。即

 ModifiedFTPSClient ftpClient = new ModifiedFTPSClient(true);
    ftpClient.addProtocolCommandListener(new PrintCommandListener(System.out));
    ftpClient.setTrustManager(TrustManagerUtils.getAcceptAllTrustManager());... and so on.
邬阳
2023-03-14

首先,确保连接到FTP服务器的普通端口,因为您正在FTPS explict模式下实例化FTPSClient。

您使用的Java 7在更新75之前仍然使用SSLv2Hello来启动SSL会话。在过去几年中,在SSL中发现了Heartbleed、BEAST和所有其他漏洞之后,现在大多数基于SSL的服务器都拒绝使用版本为的TLS数据包进行握手尝试

判断我是否正确的最简单方法是尝试使用Java8启动应用程序(已切换到TLS1.2)。如果成功,您需要确保停用SSLv2Hello。这可以通过使用以下系统属性调用JVM全局完成:

java -Dhttps.protocols="TLSv1,TLSv1.1,TLSv1.2" -Djdk.tls.client.protocols="TLSv1,TLSv1.1,TLSv1.2" <MyApp>

或者在进行握手之前,在套接字上设置允许的协议,如下所示:

sslSocket.setEnabledProtocols(new String[] {"TLSv1", "TLSv1.1", "TLSv1.2"});

或者将相应的SSLSocketFactory设置到FTPClient以在FTPClient需要SSLSocket时设置如上所示的协议。我不知道Apache的FTPClient,所以我无法告诉您如何做到这一点,但文档或谷歌搜索应该可以帮助您做到这一点。

但无论如何,停用SSLv2Hello是一件好事[TM],因此将JVM更新到最新版本(无论是Java 7 Update 80还是Java 8 Update 161)都不是一个坏主意,同时也可以获得所有其他与SSL无关的修复。

如果我关于SSLv2Hello的理论不正确,那么下一步唯一能帮助您解决这个问题的就是使用像Wireshark这样的TCP记录器,它可以向您显示实际的SSL握手以及对等服务器在什么时候关闭连接。通常,您可以在该跟踪中看到一个SSL警报,解释Java中收到的异常中未显示的实际问题。

 类似资料:
  • 感谢您抽出时间阅读我的问题-我正在使用EclipseIDE。我希望Jsoup连接https url-https://www.icegate.gov.in/使用 但它在线程“main”javax中给出了错误,而当我对其他https(如linkedin)使用相同的代码时,它就工作了。。。我不知道如何解决这个问题。 我获得了该网站的证书,并安装在我的jre/lib/security文件夹中,但它对我也没

  • 我正在尝试连接到SOAPendpoint。 使用上面的方法,我不断得到下面的错误 java.lang.Thread.run(未知来源)[na: 1.8。0_191]原因:com.sun.xml.messaging.saaj.SOAPExceptionImpl:消息发送失败com.sun.xml.messaging.saaj.client.p2p。HttpSOAPConnection.post(Ht

  • 我们为特定的IP地址配置了一个大型F5负载平衡器虚拟服务器,它将传入的https请求重定向到多个Windows服务器,在这些服务器上可以生成响应。 我正在使用SoapUI测试通过大F5中虚拟服务器的IP地址对这些windows服务器的访问。 使用由组织生成的服务器和客户机证书,我们在该组织中也进行了此设置,并通过SoapUI发送请求,我得到了预期的响应。 业务要求要求由Thawte签署商业证书。

  • SSLHandShakeException:尝试发布到以下URL时,在握手过程中发生远程主机关闭连接异常: https://testapi.title365.com/keystoneB2b/ordersservice.aspx 谁能帮帮忙吗?

  • 我正在尝试连接到需要“通过TLS显式FTP”的FTP并上载文件。 我正在尝试从我的本地机器上实现它,它使用Java版本8和commons net FTP版本3.6 下面是我使用的代码 下面是我从Java CommandListener获得的日志 下面是我尝试使用FileZilla连接时的日志。连接很好,我可以传送文件。 但是,当我尝试使用Java时,它不会传输数据 请大家帮忙好吗? 亲切的问候乔恩

  • 论坛上充斥着这个问题,但我找不到解决办法。我尝试连接WS,但没有成功。我试图更新cacerts文件,但没有效果。 日志是: 谢谢你的帮助