如何使用相同的TLS会话连接到具有数据连接的FTPS服务器?
环境:我在64位Windows 7上使用Sun Java JDK 1.8.0_60,使用Spring Integration 4.1.6(内部似乎使用Apache Commons Net 3.3进行FTPS访问)。
我正在尝试与我们的应用程序集成,从我们客户端的FTPS服务器自动下载。我已经成功地使用Spring Integration的SFTP服务器做到了这一点,没有遇到任何问题,但这是客户端第一次要求我们使用FTPS,并且让它连接是非常令人费解的。虽然在我的实际应用程序中,我使用XML bean配置Spring Integration,但为了尝试理解什么不起作用,我使用以下测试代码(尽管我在这里匿名化了实际的主机/用户名/密码):
final DefaultFtpsSessionFactory sessionFactory = new DefaultFtpsSessionFactory();
sessionFactory.setHost("XXXXXXXXX");
sessionFactory.setPort(990);
sessionFactory.setUsername("XXXXXXX");
sessionFactory.setPassword("XXXXXXX");
sessionFactory.setClientMode(2);
sessionFactory.setFileType(2);
sessionFactory.setUseClientMode(true);
sessionFactory.setImplicit(true);
sessionFactory.setTrustManager(TrustManagerUtils.getAcceptAllTrustManager());
sessionFactory.setProt("P");
sessionFactory.setProtocol("TLSv1.2");
sessionFactory.setProtocols(new String[]{"TLSv1.2"});
sessionFactory.setSessionCreation(true);
sessionFactory.setCipherSuites(new String[]{"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"});
final FtpSession session = sessionFactory.getSession();
//try {
final FTPFile[] ftpFiles = session.list("/");
logger.debug("FtpFiles: {}", (Object[]) ftpFiles);
//} catch (Exception ignored ) {}
session.close();
我正在运行此代码以获取打印的所有TLS调试信息。-Djavax.net.debug=all
与FTPS服务器的主要“控制”连接工作正常,但是当它尝试打开列表的数据连接(或我尝试过的任何其他数据连接)时,我得到一个,由 引起。如果我在命令周围取消注释吞噬异常捕获块,那么我可以看到(通过javax.net.debug输出)服务器在拒绝数据连接SSL握手后发送了以下消息:javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
java.io.EOFException: SSL peer shut down incorrectly
session.list
main, READ: TLSv1.2 Application Data, length = 129
Padded plaintext after DECRYPTION: len = 105
0000: 34 35 30 20 54 4C 53 20 73 65 73 73 69 6F 6E 20 450 TLS session
0010: 6F 66 20 64 61 74 61 20 63 6F 6E 6E 65 63 74 69 of data connecti
0020: 6F 6E 20 68 61 73 20 6E 6F 74 20 72 65 73 75 6D on has not resum
0030: 65 64 20 6F 72 20 74 68 65 20 73 65 73 73 69 6F ed or the sessio
0040: 6E 20 64 6F 65 73 20 6E 6F 74 20 6D 61 74 63 68 n does not match
0050: 20 74 68 65 20 63 6F 6E 74 72 6F 6C 20 63 6F 6E the control con
0060: 6E 65 63 74 69 6F 6E 0D 0A nection..
似乎正在发生的事情(这是我第一次处理FTPS,尽管我以前处理过普通FTP)是服务器确保控制和数据连接上的身份验证和加密的方式是,在“正常”TLS连接建立控制连接并在那里进行身份验证之后,每个数据连接都要求客户端使用相同的TLS会话进行连接。这对我来说是有道理的,因为它应该如何工作,但Apache Commons Net FTPS实现似乎并没有这样做。它似乎正在尝试建立新的TLS会话,因此服务器正在拒绝该尝试。
基于这个关于在 JSSE 中恢复 SSL 会话的问题,Java 似乎为每个主机/后置组合假定或需要不同的会话。我的假设是,由于FTPS数据连接与控制连接位于不同的端口上,因此它没有找到现有会话并尝试建立新会话,因此连接失败。
我看到了三种主要的可能性:
- 服务器不遵循 FTPS 标准,要求数据端口上的 TLS 会话与控制端口上的 TLS 会话相同。我可以使用FileZilla 3.13.1很好地连接到服务器(使用与我尝试在代码中使用的相同的主机/用户/密码)。服务器在登录时将自己标识为“FileZilla Server 0.9.53 beta”,所以也许这是某种专有的FileZilla做事方式,我需要做一些奇怪的事情来说服Java使用相同的TLS会话。
- Apache Commons Net客户端实际上并不遵循FTPS标准,只允许一些不允许保护数据连接的子集。这似乎很奇怪,因为它似乎是从Java内部连接到FTPS的标准方式。
- 我完全错过了一些东西,并误诊了这一点。
我很感激你能提供任何关于如何连接到这种FTPS服务器的方向。谢谢。