You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:01:37