【问题标题】:Transfer files from android with FTPS to the server [duplicate]使用FTPS将文件从android传输到服务器[重复]
【发布时间】:2018-07-20 03:07:27
【问题描述】:

我在我的安卓应用程序中使用Apache Commons FTP library

我是通过 FTPS 建立连接,虽然可以完美连接到服务器,但传输文件时出现问题。

订购应用程序的客户端出于安全原因,请求在使用 PROT P 时请求数据连接上的 TLS 会话恢复。

因此,我在服务器上启用了这个选项:

正如我所说,我可以连接到服务器,但不能传输文件。 如果我取消激活“使用 PROT P 时数据连接需要 TLS 会话恢复”框,则传输正常。

我正在寻找一种使用该库进行文件传输的方法,但是没有成功,但是,我知道必须有一种方法。

我给你部分相关代码:

TransferImagenesFTP.ftpClient = new FTPSClient();

TransferImagenesFTP.ftpClient.connect(InetAddress.getByName("XXX_XXX_XX_X"), 26);
TransferImagenesFTP.ftpClient.enterLocalPassiveMode();
TransferImagenesFTP.ftpClient.setBufferSize(1024000);
TransferImagenesFTP.ftpClient.login("xxxxxx", "zzzzzz");
TransferImagenesFTP.ftpClient.execPROT("P");
TransferImagenesFTP.ftpClient.type(FTP.BINARY_FILE_TYPE);

感谢任何帮助,谢谢。

【问题讨论】:

标签: java android ftp-client ftps apache-commons-net


【解决方案1】:

您的问题是 the Apache FTPSClient 不支持 TLS 会话恢复,因此在您尝试传输文件时失败。

了解问题

当您通过 TLS 连接到 FTP 服务器时,服务器会在 控制连接 上与客户端发起 安全 ssl 会话。然后客户端通过发送PASV 命令进入被动模式,作为响应,服务器打开一个随机的非特权端口,并将端口号作为响应发送给客户端。此端口代表数据连接。现在要安全地连接到这个新端口,客户端必须重用它在 控制连接 上与服务器已有的现有 TLS 会话。

为什么要重用 TLS 会话?

不需要会话恢复允许会话窃取攻击。 FTP 的问题是数据连接没有对客户端进行身份验证。
如果服务器/客户端不重用现有的 TLS 会话,则攻击者可能会转而连接到数据端口并上传恶意软件。所以为了防止这种攻击,FTP服务器要求客户端重用已经建立的会话。

在您的情况下,the Apache FTPSClient 未能重用会话(它是 known issue),因此服务器认为您的客户端未经授权并拒绝传输。

查看Wealthfront post,了解如何修补和示例实现。

来源:

  • 财富前沿 [link]
  • Slacksite [link]
  • FlieZilla 论坛 [link]

【讨论】:

  • 和我得出的结论差不多,非常感谢。
  • 据我所见,FTPS/FTPES 服务器还需要一个数据通道与控制通道源自相同的 IP 地址,才能使用它。由于 FTP 通过 TCP 运行,您不必担心 IP 地址欺骗,因此此漏洞的攻击面减少到 NAT 网关(例如 VPN、几乎每个人的防火墙等)。为了使这种攻击起作用(当不需要 TLS 会话恢复时),攻击者必须在与受害者相同的 NAT'ing 网关后面。
【解决方案2】:

您可以尝试以下代码,希望它也适用于您的情况。

代码使用 Apache Commons vsf2 通过安全 ftp 连接 (SFTP) 上传文件

try {
  String filepath = "<FILE PATH>";
  String serverAddress = "<FTP SERVER ADDRESS>";
  String userId = "<FTP USER ID>";
  String password = "<FTP PASSWORD>";
  String remoteDirectory = "<FTP DIRECTORY TO UPLOAD TO>";   
  String keyPath = "<PATH TO YOUR KEY>";   
  String passPhrase = "<PASSWORD FOR YOUR KEY>";   


  File file = new File(filepath);
  if (!file.exists())
    throw new RuntimeException("Error. File not found");

  //Initializes the file manager
  StandardFileSystemManager manager = new StandardFileSystemManager();
  manager.init();

  //Setup our SFTP configuration
  FileSystemOptions opts = new FileSystemOptions();
  SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(opts, "no");
  SftpFileSystemConfigBuilder.getInstance().setUserDirIsRoot(opts, true);
  SftpFileSystemConfigBuilder.getInstance().setTimeout(opts, 10000);

  // Create local file object
  FileObject localFile = manager.resolveFile(file.getAbsolutePath());

  // Create remote file object
  FileObject remoteFile = manager.resolveFile(createConnectionString(serverAddress, userId, password, keyPath, passPhrase, fileToFTP), createDefaultOptions(keyPath, passPhrase));


  // Copy local file to sftp server
  remoteFile.copyFrom(localFile, Selectors.SELECT_SELF);
  System.out.println("File upload successful");

}
catch (Exception ex) {
  ex.printStackTrace();
  return false;
}
finally {
  manager.close();
}

您可以在Apache Commons VFS Documentation查看更多信息

已编辑

在了解 FTPS 背后的逻辑和 @riyaz-ali 的帖子后,并在您的评论中引用链接到 this article

Apache FTP 客户端有问题,它不支持 TLS 会话恢复。您可以修补 Apache Commons Library 的现有实现。

您可以尝试以下代码步骤以使其正常工作:

  1. 在您的项目中添加以下修补类。 (该类扩展了 Apache commons 中给出的现有 FTPS 实现并带有补丁)

    import java.io.IOException;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.net.Socket;
    import java.util.Locale;
    
    import javax.net.ssl.SSLSession;
    import javax.net.ssl.SSLSessionContext;
    import javax.net.ssl.SSLSocket;
    
    import org.apache.commons.net.ftp.FTPSClient;
    
    import com.google.common.base.Throwables;
    
    public class PatchedFTPSClient extends FTPSClient {
    
            @Override
            protected void _prepareDataSocket_(final Socket socket) throws IOException {
                    if(socket instanceof SSLSocket) {
                            final SSLSession session = ((SSLSocket) _socket_).getSession();
                            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);
                                    final String key = String.format("%s:%s", socket.getInetAddress().getHostName(),
                                                                                                    String.valueOf(socket.getPort())).toLowerCase(Locale.ROOT);
                                    method.invoke(cache, key, session);
                            } catch(Exception e) {
                                    throw Throwables.propagate(e);
                            }
                    }
            }
    
    }
    
  2. 使用这个修改过的代码sn-p。

    TransferImagenesFTP.ftpClient = new PatchedFTPSClient();
    
    TransferImagenesFTP.ftpClient.connect(InetAddress.getByName<SERVER-ADDRESS>"), 26);
    TransferImagenesFTP.ftpClient.login("<USERNAME>", "<PASSWORD>");
    TransferImagenesFTP.ftpClient.execPBSZ(0);
    TransferImagenesFTP.ftpClient.execPROT("P");
    TransferImagenesFTP.ftpClient.enterLocalPassiveMode();
    
    //Now use the FTP client to upload the file as usual.
    

    希望这对您有用并能解决您的问题。

【讨论】:

  • 这是在SFTP下使用的解决方案,我需要在FTPS下传输文件。还是谢谢你。
  • 不幸的是,这个解决方案仍然不起作用。谢谢
  • 我已经在桌面 (ubuntu) 上的 Java 8 VM 上成功测试了 @NahidAli 的解决方案,并且运行良好。我已上传a Gist,请查看。我会在 Android 上测试后更新我的答案。
  • 我在 mac 下使用 Java 8 update 161 尝试过同样的要点,但它不起作用:(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-04
  • 2020-05-14
  • 2019-07-12
  • 1970-01-01
相关资源
最近更新 更多