【问题标题】:How to establish a FTPS data connection to a FileZilla Server 1.2.0如何建立到 FileZilla Server 1.2.0 的 FTPS 数据连接
【发布时间】:2022-01-29 09:25:21
【问题描述】:

使用 Apache commons-net 的 Java FTPSClient 进行会话恢复是一个已知问题。会话恢复是 FTPS 服务器数据连接可能需要的一项安全功能。 Apache FTPSClient 不支持会话恢复,JDK API 使得构建自定义实现变得困难。有几个使用反射的解决方法,请参见例如this answer 和这个commons-net bug entry

我在 JDK 11 中使用了这样的解决方法(参见下面的片段),并针对本地 FileZilla 服务器对其进行了测试。它适用于 FileZilla Server 0.9.6,但不适用于 FileZilla Server 1.2.0,这是撰写本文时的最新版本。在该版本中,当尝试建立数据连接时,服务器会响应:

425 Unable to build data connection: TLS session of data connection not resumed.

正如我所说,FileZilla Server 0.9.6 对我如何恢复会话没有问题,并且我确保激活了要求会话恢复的设置。

在 FileZilla Server 1.2.0 中,这些设置现在是隐式设置的,不能通过 GUI 更改,也许根本不能更改。我可以调整一些服务器设置以使其正常工作吗?还是我如何实施解决方法有问题?有没有人遇到过类似的问题?

这是我正在使用的解决方法:

public class FTPSClientWithSessionResumption extends FTPSClient {

    static {
        System.setProperty("jdk.tls.useExtendedMasterSecret", "false");
        System.setProperty("jdk.tls.client.enableSessionTicketExtension", "false");
    }

    @Override
    protected void _connectAction_() throws IOException {
        super._connectAction_();
        execPBSZ(0);
        execPROT("P");
    }

    @Override
    protected void _prepareDataSocket_(Socket socket) throws IOException {
        if (useSessionResumption && socket instanceof SSLSocket) {
            // Control socket is SSL
            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 putMethod = cache.getClass().getDeclaredMethod("put", Object.class, Object.class);
                    putMethod.setAccessible(true);
                    Method getHostMethod;
                    try {
                        getHostMethod = socket.getClass().getMethod("getPeerHost");
                    }
                    catch (NoSuchMethodException e) {
                        // Running in IKVM
                        getHostMethod = socket.getClass().getDeclaredMethod("getHost");
                    }
                    getHostMethod.setAccessible(true);
                    Object peerHost = getHostMethod.invoke(socket);
                    InetAddress iAddr = socket.getInetAddress();
                    int port = socket.getPort();
                    putMethod.invoke(cache, String.format("%s:%s", peerHost, port).toLowerCase(Locale.ROOT), session);
                    putMethod.invoke(cache, String.format("%s:%s", iAddr.getHostName(), port).toLowerCase(Locale.ROOT), session);
                    putMethod.invoke(cache, String.format("%s:%s", iAddr.getHostAddress(), port).toLowerCase(Locale.ROOT), session);
                }
                catch (Exception e) {
                    throw new IOException(e);
                }
            }
            else {
                throw new IOException("Invalid SSL Session");
            }
        }
    }
}

使用getPeerHostgetInetAddress().getHostName()getInetAddress().getHostAddress() 确定缓存套接字的地址。我尝试了几种做或不做这三个的组合,但我总是得到相同的结果。

编辑

这是完整会话的服务器日志截图:

【问题讨论】:

  • 第一个数据连接是否已经失败(包括目录列表)?还是只有后续的数据连接? FileZilla Server 1.x 具有此处讨论的特性:forum.filezilla-project.org/viewtopic.php?t=54027 + 要缩小问题范围,请尝试在 Java 端禁用 TLS 1.3(在 FileZilla 服务器上允许 TLS 1.2 之后),检查这是否是 TLS 1.3 问题(afaik,FileZilla 服务器0.x 不支持 TLS 1.3)。 TLS 1.3 要复杂得多,可能需要稍后重新启动 TLS 会话。
  • Afaik,FileZilla Server 1.x 的 TLS 实现(libssl?)与 0.x(OpenSSL)完全不同。 libssl 和其他 TLS 实现(尤其是 OpenSSL)之间似乎存在互操作性问题。添加对 TLS 1.3 的新支持,你会遇到很多麻烦 :)
  • 好点! AFAICT,第一个数据连接已经失败。我附上了服务器日志的屏幕截图。使用 TLS 1.2,一切正常,所以真正的解决方法不适用于 TLS 1.3。是否有一些已知的解决方法有效?

标签: java filezilla ftps apache-commons-net session-reuse


【解决方案1】:

正如 StackOverflow 帖子中所述,可以告诉 JVM 只应使用 TLS 1.2。
这是对我有用的原始答案的链接:command for java to use TLS1.2 only

在这种情况下,您必须在 JVM 的开头添加一个命令行参数:java -Djdk.tls.client.protocols=TLSv1.2 -jar ... <rest of command line here>

这个简单的参数对我有用,现在我可以从运行 FileZilla FTP-Server 1.3.0 的 FTP-Server 连接和传输数据

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-08
    • 2012-06-02
    • 2012-03-07
    • 2015-07-16
    • 1970-01-01
    • 2017-10-20
    相关资源
    最近更新 更多