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

如何使用相同的TLS会话连接到具有数据连接的FTPS服务器?

公良光熙
2023-03-14
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();
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..

似乎正在发生的事情(这是我第一次处理FTP,尽管我以前处理过普通的FTP),是服务器在控制连接和数据连接上确保身份验证和加密的方式是,在建立控制连接和身份验证的“正常”TLS连接发生之后,每个数据连接都需要html" target="_blank">客户端与相同的TLS会话进行连接。这对我来说是有意义的,因为它应该如何工作,但Apache Commons Net FTPS实现似乎没有做到这一点。它似乎试图建立一个新的TLS会话,因此服务器拒绝了该尝试。

基于这个关于在JSSE中恢复SSL会话的问题,Java似乎为每个主机/POST组合假设或要求不同的会话。我的假设是,由于FTPS数据连接与控制连接在不同的端口上,它没有找到现有的会话,而是试图建立一个新的会话,因此连接失败。

我认为有三种主要的可能性:

  1. 服务器没有遵循FTPS标准,在数据端口上需要与控制端口上相同的TLS会话。我可以使用FileZilla 3.13.1很好地连接到服务器(使用与我在代码中尝试使用的相同的主机/用户/密码)。服务器在登录时将自己标识为“FileZilla server 0.9.53 beta”,所以这可能是某种专有的FileZilla方式,我需要做一些奇怪的事情来说服Java使用相同的TLS会话。
  2. Apache Commons Net客户端实际上并不遵循FTPS标准,只允许一些不允许保护数据连接的子集。这看起来很奇怪,因为这似乎是从Java内部连接到FTPS的标准方式。
  3. 我完全错过了一些东西,误诊了。

共有1个答案

阳宗清
2023-03-14

实际上,一些FTP服务器确实要求TLS/SSL会话被重用用于数据连接。这是一种安全措施,服务器可以通过它验证数据连接与控制连接是由同一客户端使用的。

常见FTP服务器的一些参考:

    null
  @Override
  protected void _prepareDataSocket_(final Socket socket) throws IOException {
      if(preferences.getBoolean("ftp.tls.session.requirereuse")) {
          if(socket instanceof SSLSocket) {
              // Control socket is SSL
              final SSLSession session = ((SSLSocket) _socket_).getSession();
              if(session.isValid()) {
                  final SSLSessionContext context = session.getSessionContext();
                  context.setSessionCacheSize(preferences.getInteger("ftp.ssl.session.cache.size"));
                  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) {
                      // Not running in expected JRE
                      log.warn("No field sessionHostPortCache in SSLSessionContext", e);
                  }
                  catch(Exception e) {
                      // Not running in expected JRE
                      log.warn(e.getMessage());
                  }
              }
              else {
                  log.warn(String.format("SSL session %s for socket %s is not rejoinable", session, socket));
              }
          }
      }
  }

对重用的本机支持仍然待定:
https://issues.apache.org/jira/browse/net-408

System.setProperty("jdk.tls.useExtendedMasterSecret", "false");

实际上我在过去也遇到过同样的问题(只是在C++/OpenSSL中,我不做Java),所以我知道谷歌是为了什么。

 类似资料:
  • 我正在我的android应用程序中使用Apache Commons FTP库。 我正在使用带有JDK1.8的Android studio。 我很感激任何帮助,谢谢。

  • 问题内容: 我被困在通过TLS / SSL(FTPS)服务器连接到FTP上。我正在通过SimpleFTP库使用能够连接不带SSL的FTP服务器,但无法连接FTPS的情况。 它在第2行(ftp.connect)上给了我这个错误, 连接到FTP服务器时,SimpleFTP收到未知响应: 220 ----------欢迎使用Pure-FTPd [privsep] [TLS] ---------- 并正在

  • 我无法通过TLS/SSL(FTPS)服务器连接到FTP。我正在使用SimpleFTP库,通过我可以连接没有SSL的FTP服务器,但不能连接FTPS。 它在第2行(ftp.connect)给出了这个错误, SimpleFTP连接到FTP服务器时收到未知响应: 220---------欢迎使用Pure-FTPd[privsep][TLS]--------- 并且正在使用下面的代码

  • 我使用istio 1.0.2版本与istio-demo-auth.yaml,我有一个mssql db外面的k8s群集,我想连接它形成istio注入服务。我尝试使用此消耗外部TCP服务博客,但服务无法连接到外部mssql实例。服务条目如下: 服务日志显示“预登录错误:主机mssql-master端口2433读取预登录响应错误:连接重置ClientConnectionId:”,似乎根本没有到达mssq

  • 我正在尝试使用ftp4j lib从FileZilla FTP servcer中获取带有TLS的文件列表。 我有个例外 线程“main”it.sauronsoftware.ftp4j.ftpexception异常[代码=450,消息=TLS数据连接会话未恢复或会话与控制连接不匹配]位于ftp.main(ftp.java:49)的it.sauronsoftware.ftp4j.ftpclient.li

  • 问题内容: 我在跟踪为什么无法连接到特定主机时遇到问题。 通过curl或浏览器,以下命令可以正常工作: 但是,如果我使用请求: 我得到: 在网络上,我仅看到客户端问好,服务器立即断开连接,因此似乎没有任何ssl或密码不兼容。(我希望这些都是SSL层错误)在这种情况下还有什么其他问题? 我在python 3.6.1上,请求2.14.2(带有安全性额外功能)。 问题答案: 该服务器以多种方式损坏。 一