Search code examples
javaftpftpsapache-commons-net

SSL Session reuse in Apache FTPS client in JDK 8u161


Using Apache Commons-Net's FTPSClient to connect to a modern FTP/S server does not work. The reason is that they require SSL session reuse, i.e. the SSL session from the control connection needs to be re-used for the data connection.

This can usually be deactivated in the server, but that is

  • insecure
  • not always an option (since the server might not be under your control)

The correct solution would be to make the client actually re-use sessions. There is an open bug for Commons-Net but it does not look like that is going to be resolved any time soon.

Also, there is a "reflection hack" that was created by the authors of Cyberduck (an FTP client application) which is described in their bugtracker and, more in-depth, in a blog post. There is also a related post on StackOverflow describing this solution. They use reflection to access the internal cache of the JDK's SSLSessionContext and inject a new entry.

This hack worked fine until JDK 8u161 and 9.0.4 (?) where some changes to SSL were introduced that are described in the changelog. Apparently, some implementation details have changed causing the hack to not work any more.

As far as I can tell, there are the following options now:

  • Stay on JDK 8u152 either until someone finds a solution/apache-commons-net gets patched/JDK changes get rolled back (not really an option, because that would cut off production systems from security updates)
  • Use a different FTPS client (the only alternative I could find is proprietary and quite expensive)
  • Try to reverse engineer the changes to the SSLSessionContext implementation to find a new workaround. Not only does this seem like a non-trivial task - a solution would likely be hacky again and is thus likely to break again any time.
  • Do not use FTP/S any more

Can anyone suggest how to proceed here?


Related links:


Solution

  • A possible solution is described here.

    Essentially, it is reverting changed behavior from JDK8u161 to the way this worked before. You need to set the system property

    jdk.tls.useExtendedMasterSecret
    

    to false to do that.

    There are two ways:

    • call System.setProperty("jdk.tls.useExtendedMasterSecret", "false"); before initiating the FTP/S connection
    • Pass the property to your java process with java -Djdk.tls.useExtendedMasterSecret=false [...]

    Keep in mind that this solution disables a security enhancement JVM-wide - proceed with caution.