Apache SSHD Client获取SSH服务器公钥返回null,求解决方法
如何通过Apache SSHD Client正确获取SSH服务器公钥?
你的代码之所以返回null,核心问题是调用时机不对——getKex().getServerKey()只有在密钥交换(Kex)流程完全完成后才会返回有效公钥,而你当前的链式调用在connect().verify()后直接去拿,这时密钥交换还没真正触发完成。
下面是正确的实现方式,分步骤说明:
- 先完成会话启动与密钥交换:不要急于链式调用到底,先获取会话对象,然后等待会话进入「等待认证」状态——这个状态意味着密钥交换已经完成,服务器公钥已经协商完毕。
- 安全管理资源:用try-with-resources语法确保客户端和会话资源被正确关闭,避免泄漏。
完整的可运行示例代码如下:
import org.apache.sshd.client.SshClient; import org.apache.sshd.client.session.ClientSession; import org.apache.sshd.client.session.WaitForResult; import java.security.PublicKey; import java.util.EnumSet; import java.util.concurrent.TimeUnit; import java.util.Base64; public class SshServerKeyRetriever { public static void main(String[] args) { try (SshClient sshClient = SshClient.setUpDefaultClient()) { sshClient.start(); // 建立连接并获取会话实例 ClientSession session = sshClient.connect("dyn mem", "localhost", 2222) .verify(10, TimeUnit.SECONDS) .getSession(); try { // 等待会话完成密钥交换,进入等待认证状态 WaitForResult waitResult = session.waitFor( EnumSet.of(ClientSessionEvent.WAIT_AUTH), TimeUnit.SECONDS.toMillis(10) ); if (waitResult.isSuccess()) { // 此时密钥交换已完成,安全获取服务器公钥 PublicKey serverPublicKey = session.getKex().getServerKey(); if (serverPublicKey != null) { // 示例:输出公钥信息 System.out.println("服务器公钥算法: " + serverPublicKey.getAlgorithm()); System.out.println("Base64编码的公钥: " + Base64.getEncoder().encodeToString(serverPublicKey.getEncoded())); } else { System.err.println("未能获取服务器公钥,请检查服务器配置或连接参数"); } } else { System.err.println("会话密钥交换超时或失败,无法获取公钥"); } } finally { // 确保会话关闭 session.close(); } } catch (Exception e) { e.printStackTrace(); } } }
额外的注意事项:
- 确保你使用的Apache SSHD版本是2.8.0及以上,旧版本的Kex API可能存在兼容性问题。
- 如果你的服务器使用了特殊的密钥交换算法,可以在启动客户端前通过
sshClient.setKeyExchangeFactories()自定义支持的算法集合。 - 不要跳过
waitFor步骤直接去拿公钥,这会导致你拿到的是未初始化的Kex对象,返回null。
内容的提问来源于stack exchange,提问作者Jan Wytze
相关产品推荐
相关产品推荐

