通过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;
额外注意事项
- 生产环境安全建议:不要一直用
StrictHostKeyChecking: no,这会跳过主机密钥校验,有安全风险。建议改为ask,然后在UserInfo的promptYesNo方法里做手动确认逻辑。 - UserInfo实现:JSch的
UserInfo是接口,必须实现所有抽象方法,否则会在认证过程中抛出异常,你之前的代码里可能只设置了密码,其他方法没实现,这也可能导致潜在问题。 - 密钥匹配:如果你的本地
known_hosts文件里已经有host1.com的密钥,设置hostKeyAlias后,JSch会自动匹配该密钥,无需额外操作。
内容的提问来源于stack exchange,提问作者Rajar R
相关产品推荐
相关产品推荐

