mpe*_*old 5 java filezilla ftps apache-commons-net session-reuse
使用 Apache commons-net 的 Java FTPSClient 进行会话恢复是一个已知问题。会话恢复是 FTPS 服务器数据连接所需的一项安全功能。Apache FTPSClient 不支持会话恢复,并且 JDK API 使得构建自定义实现变得困难。有一些使用反射的解决方法,请参阅此答案和此commons-net bug 条目。
我在 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.
Run Code Online (Sandbox Code Playgroud)
正如我所说,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");
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
getPeerHost使用、getInetAddress().getHostName()和确定套接字缓存的地址getInetAddress().getHostAddress()。我尝试了执行或不执行这三项的几种组合,但总是得到相同的结果。
编辑:
以下是完整会话的服务器日志的屏幕截图:
正如 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 服务器连接并传输数据
| 归档时间: |
|
| 查看次数: |
2386 次 |
| 最近记录: |