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

通过JSch跳板机SSH连接目标主机时遭遇reject HostKey异常

解决JSch跳板机端口转发的HostKey拒绝问题

我来帮你搞定这个问题:你通过JSch实现跳板机连接目标主机时,遇到的reject HostKey: 127.0.0.1异常,本质是JSch在连接本地转发端口(127.0.0.1)时,默认会校验本地主机的密钥,但你实际需要校验的是目标主机host1.com的密钥。虽然你设置了hostKeyAlias,但因为配置不完整,导致这个别名没起作用。

问题核心

当你用端口转发把本地端口映射到目标主机的22端口后,连接127.0.0.1:assignedPort时,JSch会默认去匹配127.0.0.1的主机密钥,而不是host1.com的。哪怕你设置了hostKeyAlias,如果没给目标会话配置正确的密钥校验规则,依然会触发拒绝。

修复方案

你需要做两个关键调整:

  • 给目标主机的会话也配置密钥校验规则(和跳板机会话类似)
  • 确保hostKeyAlias正确关联到目标主机,让JSch用目标主机的密钥来校验

修正后的完整代码

Session[] sessions = new Session[2];
Session jumpSession = null;

// 第一步:建立跳板机会话
jumpSession = jsch.getSession(getUserName(), "jumphost1.com", 22);
jumpSession.setPassword(getHostPassword());

// 实现完整的UserInfo(JSch的UserInfo是接口,必须实现所有方法)
UserInfo userInfo = new UserInfo() {
    @Override
    public String getPassword() {
        return getHostPassword();
    }

    @Override
    public boolean promptPassword(String message) {
        // 自动确认密码提示(生产环境可根据需求调整)
        return true;
    }

    @Override
    public boolean promptYesNo(String message) {
        // 自动确认主机密钥等yes/no提示(生产环境建议改为手动确认)
        return true;
    }

    @Override
    public void showMessage(String message) {
        LOGGER.info("JSch提示:{}", message);
    }

    @Override
    public String getPassphrase() {
        return null; // 如果你不用密钥对认证,这里返回null即可
    }

    @Override
    public boolean promptPassphrase(String message) {
        return true;
    }
};

jumpSession.setUserInfo(userInfo);
Properties jumpProp = new Properties();
jumpProp.put("StrictHostKeyChecking", "no"); // 生产环境建议改为"ask"或"yes",更安全
jumpProp.put("PreferredAuthentications", "publickey,keyboard-interactive,password");
jumpSession.setConfig(jumpProp);
jumpSession.connect();
LOGGER.info("跳板机jumphost1.com连接成功");

// 第二步:配置本地端口转发
String targetHost = "host1.com";
int assignedPort = jumpSession.setPortForwardingL(0, targetHost, 22);
LOGGER.info("已建立端口转发:本地端口{} → 目标主机{}:22", assignedPort, targetHost);

// 第三步:连接目标主机(通过本地转发端口)
Session targetSession = jsch.getSession(getUserName(), "127.0.0.1", assignedPort);
targetSession.setPassword(getHostPassword());
targetSession.setUserInfo(userInfo);

// 关键:给目标会话配置校验规则,并设置主机密钥别名
Properties targetProp = new Properties();
targetProp.put("StrictHostKeyChecking", "no"); // 生产环境调整为更严格的规则
targetProp.put("PreferredAuthentications", "publickey,keyboard-interactive,password");
targetSession.setConfig(targetProp);
targetSession.setHostKeyAlias(targetHost); // 告诉JSch,用目标主机的密钥来校验这个连接

// 连接目标主机
targetSession.connect();
LOGGER.info("成功连接至目标主机{}", targetHost);

// 保存会话到数组,方便后续关闭
sessions[0] = jumpSession;
sessions[1] = targetSession;

额外注意事项

  1. 生产环境安全建议:不要一直用StrictHostKeyChecking: no,这会跳过主机密钥校验,有安全风险。建议改为ask,然后在UserInfo的promptYesNo方法里做手动确认逻辑。
  2. UserInfo实现:JSch的UserInfo是接口,必须实现所有抽象方法,否则会在认证过程中抛出异常,你之前的代码里可能只设置了密码,其他方法没实现,这也可能导致潜在问题。
  3. 密钥匹配:如果你的本地known_hosts文件里已经有host1.com的密钥,设置hostKeyAlias后,JSch会自动匹配该密钥,无需额外操作。

内容的提问来源于stack exchange,提问作者Rajar R

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:07:44