Java【问题 07】SSH不同版本使用jsch问题处理(7.4升级9.7及欧拉原生8.8)

本文总结了使用jsch库连接不同版本SSH时遇到的三个典型问题及解决方案。

    1. OpenSSH 8.8版本算法协商失败问题,通过修改sshd_config添加ssh-rsa算法解决;
    1. OpenSSH 9.7升级后出现的认证和SFTP问题,发现是异步执行命令导致目录未创建,通过增加连接状态检查循环修复;
    1. 连接超时和包损坏问题,通过增加超时时间和重建session对象解决。

这些问题都与SSH版本升级和异步操作时序相关,通过调整配置和优化代码逻辑得以解决。

1.问题一

bash 复制代码
# 1.系统
cat /etc/os-release
# 系统信息
NAME="openEuler"
VERSION="22.03 (LTS-SP1)"
ID="openEuler"
VERSION_ID="22.03"
PRETTY_NAME="openEuler 22.03 (LTS-SP1)"
ANSI_COLOR="0;31"

# 2.ssh
ssh -V
# ssh信息
OpenSSH_8.8p1, OpenSSL 1.1.1m  14 Dec 2021
bash 复制代码
# 1.Java报错
com.jcraft.jsch.JSchException: Algorithm negotiation fail

# 2.使用 systemctl status sshd 查看状态
Unable to negotiate with xxx.xxx.x.xxx port xxxxx: no matching host key type found. 
Their offer: ssh-rsa,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha>

问题解决:

  • 配置文件sshd_configHostKeyAlgorithms添加算法ssh-rsa
bash 复制代码
HostKeyAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-256,rsa-sha2-512,ssh-rsa

2.问题二

2.1 说明

OpenSSH是从原本的OpenSSH_7.4p1, OpenSSL 1.0.2k-fips 26 Jan 2017升级到 OpenSSH_9.7p1, OpenSSL 3.2.0 23 Nov 2023,当前环境如下:

bash 复制代码
# 1.系统
CentOS Linux release 7.8.2003 (Core)

# 2.ssh -V
OpenSSH_9.7p1, OpenSSL 3.2.0 23 Nov 2023
bash 复制代码
# 1.密码错误时Java报错信息
cn.hutool.extra.ssh.JschRuntimeException: JSchException: Auth fail
# 密码修改正确后 systemctl status sshd 查看状态
Accepted password for root from 123.160.246.239 port 22838 ssh2

# 2.通过sftp上传文件时
cn.hutool.extra.ssh.JschRuntimeException: JSchException: channel is not opened.
# 过一会儿后 systemctl status sshd 查看状态
error: no more sessions

代码进行调试,发现报错的位置:

java 复制代码
// 报错行
channelSftp.put(fs, directory, ChannelSftp.OVERWRITE);
// 报错信息
com.jcraft.jsch.SftpException: No such file

我一度认为是传输模式的问题,在ChannelSftp.put(InputStream src, String dst, int mode)方法中,mode参数用于指定文件传输模式,其可选值有:

  • ChannelSftp.OVERWRITE:这是默认的传输模式,它会完全覆盖目标服务器上的同名文件。如果目标文件不存在,则会创建一个新的文件。
  • ChannelSftp.RESUME :这种模式下,如果传输被中断,那么在下次调用put方法时,会从上一次中断的地方继续传输,而不是重新开始传输整个文件。
  • ChannelSftp.APPEND:此模式允许你将数据追加到目标服务器上的现有文件中,而不是覆盖它。如果目标文件不存在,则会创建一个新的文件。

换用其他模式依然报错。

2.2 解决

最终发现是代码的问题:

java 复制代码
// 进行代码调试时发现远程登录耗时较久
SshClient.getInstance().sshRemoteCallLoginByTool(sshHost, sshPort, sshUserName, sshPassword);
// 导致创建目标目录时未执行
SshClient.getInstance().execCommandByTool("mkdir " + targetPath);

execCommandByTool方法的原始代码:

java 复制代码
 /**
  * 执行命令
  *
  * @param command 命令
  */
 public String execCommandByTool(String command) {
     boolean isConnected = checkConnectionStatus();
     if (isConnected) {
         return JschUtil.exec(session, command, Charsets.UTF_8);
     }
     return null;
 }

可以看出,如果登录较慢,checkConnectionStatus的状态是false则创建目录的命令未被执行,导致上传时的文件路径不存在,出现报错信息,改进如下:

java 复制代码
/**
 * 执行命令
 *
 * @param command 命令
 */
public String execCommandByTool(String command) {
    boolean isConnected = checkConnectionStatus();
    while (!isConnected) {
        isConnected = checkConnectionStatus();
    }
    return JschUtil.exec(session, command, Charsets.UTF_8);
}

3.问题三

bash 复制代码
# 连接超时异常
com.jcraft.jsch.JSchException: Session.connect: java.net.SocketTimeoutException: Read timed out
# 包损坏
com.jcraft.jsch.JSchException: Packet corrupt

异常出现的位置及处理方案:

java 复制代码
private boolean createSessionAndConnected() {
    if (session == null) {
        log.info("SSHClient createSessionAndConnected...");
        session = JschUtil.createSession(this.sshHost, this.sshPort, this.sshUser, this.sshPass);
        Properties config = new Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);
        try {
            session.connect(8000);
            // com.jcraft.jsch.JSchException: Session.connect: java.net.SocketTimeoutException: Read timed out
            // 增加超时时间 session.connect(200000);
        } catch (JSchException e) {
            // com.jcraft.jsch.JSchException: Packet corrupt
            // 使用同一个session对象再次进行连接时会报错
            // 重新连接时使用新的session对象
            session = null;
            e.printStackTrace();
            log.info("SSHClient createSessionAndConnected printStackTrace");
            return false;
        }
        log.info("SSHClient createSessionAndConnected Success!");
    }
    return this.session.isConnected();
}

4.小小的总结

OpenSSH漏洞修复之后,有些有漏洞的算法被移除了,升级OpenSSH的同时还要升级相应的算法。

相关推荐
czlczl200209251 小时前
告别 try-catch 地狱:Spring Boot 全局异常处理 (GlobalExceptionHandler) 最佳实践
java·spring boot·后端
神奇的程序员7 小时前
从已损坏的备份中拯救数据
运维·后端·前端工程化
oden7 小时前
AI服务商切换太麻烦?一个AI Gateway搞定监控、缓存和故障转移(成本降40%)
后端·openai·api
李慕婉学姐8 小时前
【开题答辩过程】以《基于Android的出租车运行监测系统设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·后端·vue
m0_740043738 小时前
SpringBoot05-配置文件-热加载/日志框架slf4j/接口文档工具Swagger/Knife4j
java·spring boot·后端·log4j
招风的黑耳9 小时前
我用SpringBoot撸了一个智慧水务监控平台
java·spring boot·后端
Miss_Chenzr9 小时前
Springboot优卖电商系统s7zmj(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·后端
期待のcode9 小时前
Springboot核心构建插件
java·spring boot·后端
2501_9216494910 小时前
如何获取美股实时行情:Python 量化交易指南
开发语言·后端·python·websocket·金融
serendipity_hky10 小时前
【SpringCloud | 第5篇】Seata分布式事务
分布式·后端·spring·spring cloud·seata·openfeign