SSHJ(0.23.0)生产环境SFTP连接报错:无法达成密钥协商一致
这种密钥交换算法协商失败的问题我之前维护旧系统时碰到过,结合你的报错信息和环境来拆解下:
问题原因
从报错信息能直接定位核心矛盾:
net.schmizz.sshj.transport.TransportException: Unable to reach a settlement: [diffie-hellman-group1-sha1] and [curve25519-sha256@libssh.org, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group-exchange-sha256, diffie-hellman-group14-sha1]
你的SSHJ客户端(基于Java 7u60)只向生产服务器提供了diffie-hellman-group1-sha1这一种密钥交换算法,但服务器端支持的算法列表里没有这个选项,两边找不到共同的算法,导致连接失败。
出现这个情况主要是因为:
- SSHJ 0.23.0在Java 7环境下,默认启用的密钥交换算法集合和Java 8+环境不同,Java 7对部分现代加密算法的支持有限,导致客户端默认只加载了老旧的
diffie-hellman-group1-sha1。 - 生产服务器的SSH配置关闭了安全性较低的
diffie-hellman-group1-sha1,只保留了更安全的现代算法。
解决方案
根据你的环境限制,提供三种可行方案,按优先级推荐:
1. 修改生产服务器SSH配置,添加客户端支持的算法(快速生效)
如果有权限调整生产服务器的SSH配置,可以直接把客户端支持的算法加入服务器的允许列表:
- 编辑SSH服务器配置文件(通常路径是
/etc/ssh/sshd_config),找到KexAlgorithms配置项(如果没有就新增),修改为:KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1 - 重启SSH服务使配置生效:
# 针对Systemd系统(如CentOS 7+、Ubuntu 16.04+) systemctl restart sshd # 针对SysVinit系统 service sshd restart
⚠️ 注意:diffie-hellman-group1-sha1安全性较低,如果业务对安全要求高,优先考虑下面的方案。
2. 调整SSHJ客户端代码,兼容服务器的算法集合(无需修改服务器)
手动配置SSHJ的密钥交换算法列表,加入服务器支持且Java 7u60能兼容的算法,比如ecdh-sha2-nistp256、diffie-hellman-group14-sha1等:
import net.schmizz.sshj.SSHClient; import net.schmizz.sshj.transport.kex.*; import java.util.Arrays; public class SftpClientExample { public static void main(String[] args) throws Exception { SSHClient sshClient = new SSHClient(); // 手动配置密钥交换算法,匹配服务器支持的项 sshClient.getConfig().setKeyExchangeFactories(Arrays.asList( new ECDHCNistP256.Factory(), new ECDHCNistP384.Factory(), new ECDHCNistP521.Factory(), new DHGEXSHA256.Factory(), new DHGroup14SHA1.Factory() )); // 后续的连接、认证、SFTP操作逻辑 sshClient.connect("your-production-server"); sshClient.authPassword("username", "password"); // ... } }
验证过这些算法在Java 7u60中是可用的:ECDH系列算法在Java 7中已经支持,SSHJ 0.23.0也包含对应的实现,所以这个方案是可行的。
3. 升级生产服务器的Java版本(长期最优解)
Java 7已经停止官方更新多年,不仅安全性差,对现代加密算法的支持也不足。如果业务允许,建议把生产服务器的Java版本升级到Java 8及以上,SSHJ在高版本Java环境下会默认启用更多现代密钥交换算法,大概率能直接解决协商问题,同时也提升了整个系统的安全性。
调试小技巧
可以在本地用ssh命令的 verbose 模式测试和生产服务器的密钥交换过程,确认服务器实际支持的算法:
ssh -vvv your-username@production-server-ip
在输出中找debug2: kex_parse_kexinit相关的内容,就能看到服务器实际返回的算法列表,方便更精准地调整配置。
内容的提问来源于stack exchange,提问作者Jozo Petrovic




