【问题标题】:FTP4j fails to use FTPES (TLS session of data connection has not resumed or the session does not match the control connection)FTP4j 使用 FTPES 失败(数据连接的 TLS 会话未恢复或会话与控制连接不匹配)
【发布时间】:2023-05-07 16:17:02
【问题描述】:

我正在尝试使用 ftp4j lib 从具有 TLS 的 FileZilla FTP 服务器获取文件列表。

import it.sauronsoftware.ftp4j.FTPClient;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.Arrays;

public class FTP {

    public static void main(String args[]) throws Exception {
        System.setProperty("http.protocols", "TLSv1,TLSv1.1,TLSv1.2"); 
        //tried to avoid closing connection during the handshake

        //load and set certificate
        KeyStore keyStore = KeyStore.getInstance("JKS");
        keyStore.load(new FileInputStream("mykeystore.jks"), "root12".toCharArray());

        FTPClient client = new FTPClient();

        SSLContext sslContext = null;
        try {
            javax.net.ssl.TrustManagerFactory tmf = javax.net.ssl.TrustManagerFactory
                    .getInstance(javax.net.ssl.KeyManagerFactory
                            .getDefaultAlgorithm());
            tmf.init(keyStore);
            sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, tmf.getTrustManagers(), new SecureRandom());
        } catch (Exception e) {
            e.printStackTrace();
        }

        SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

        client.setSSLSocketFactory(sslSocketFactory);
        client.setSecurity(FTPClient.SECURITY_FTPES);

        client.setCharset("UTF-8");
        client.setPassive(true);
        String[] arg = client.connect("localhost", 21);
        System.out.println(Arrays.toString(arg));

        client.login("admin", "pass"); //OK
        client.noop(); // aka Ping is OK
        String s = client.currentDirectory(); //OK
        client.changeDirectory("/"); //OK
        String[] files = client.listNames(); //Exception here
        System.out.println(Arrays.toString(files));
        client.disconnect(true);
    }
}

我遇到了异常

线程“main”中的异常 it.sauronsoftware.ftp4j.FTPException [code=450, message= 数据连接的 TLS 会话未恢复或 会话与控制连接不匹配] 在 it.sauronsoftware.ftp4j.FTPClient.listNames(FTPClient.java:2407) 在 FTP.main(FTP.java:49)

我尝试使用主动模式,但也无济于事(ping 命令后失败)

线程“main”中的异常 it.sauronsoftware.ftp4j.FTPException [code=421, message= 拒绝命令,请求的 IP 地址不 匹配控制连接IP。]

能否请您回答我做错了什么或者 ftp4j 库实际上支持 FTPES 和 TLS 吗?

FileZilla 服务器 TLS 配置的屏幕截图:

【问题讨论】:

    标签: java ftp filezilla ftps ftp4j


    【解决方案1】:

    ftp4j 库确实支持 FTPS/TLS。如果不是这样,你一开始就不会得到错误。

    FileZilla FTP 服务器是 FTP 服务器之一,它要求客户端重用来自 FTP 控制连接的 TLS/SSL 会话进行数据连接:
    https://svn.filezilla-project.org/filezilla?view=revision&revision=6661

    这通过使攻击者更难hijack a data connection来提高安全性。

    我不知道,虽然ftp4j是否支持重用。

    替代解决方案是:

    • 使用来自 Apache Commons Net 库的 Java FTP 客户端。虽然它本身不支持重用,但添加支持很容易。见How to connect to FTPS server with data connection using same TLS session?
    • 当您拥有 FTP 服务器时,您可以禁用重用要求。请参阅 在使用 PROT P 时要求 TLS 会话恢复数据连接 选项(在您的屏幕截图上)。虽然如上所述,但它对安全性有一些影响。

    【讨论】:

    • 第二种解决方案不合适,我无法更改 ftp 服务器的设置。第一个太复杂(迁移到 apache lib)所以它应该是合理的(例如一些证明 ftp4j 不支持 TLS)
    • 我没有说“ftp4j 不支持TLS”。当然,它确实支持它。
    • 你知道为什么我的代码不能与 filezilla 一起使用吗?
    • 因为它不会为数据连接重用控制连接的TLS会话。我相信我的回答说得很清楚。
    • 已与 fpt4j 的开发人员确认,该库不可能重用会话
    【解决方案2】:

    尝试删除这个对我有帮助的复选框。

    【讨论】:

    • 这是解决方法,但不是解决方案(我无法更改远程服务器设置)
    • 而且,我已经在我的回答中提出了这一点,所以你的回答并没有带来任何新的东西。