解决Apache Mina SSHD连接重置问题:KEX失败排查
2024-12-31 15:51:07
Apache Mina SSHD 连接重置问题排查
在构建基于 Apache Mina SSHD 的应用时,有时可能会遇到 "kex_exchange_identification: read: Connection reset by peer"
错误,这表明在 SSH 连接的密钥交换(KEX)阶段,连接被对端重置。这是一个常见的问题,以下我们将分析其可能的原因及解决方法。
问题分析
此错误通常发生在客户端与服务端建立连接后,尝试进行密钥交换的初始阶段。连接重置意味着在协商任何具体的加密或验证机制之前,连接就已经断开。发生这种情况可能有多种原因:
- 协议不兼容: 客户端和服务端所使用的 SSH 协议版本或加密算法不一致。
- 服务端配置错误: 服务端的 SSHD 配置不正确,例如缺少必要的密钥,配置了不被支持的算法等。
- 客户端问题: 客户端配置不正确或使用了不兼容的选项。
- 网络问题: 虽然可能性较低,网络基础设施中的某些问题也可能导致连接重置,比如中间网络设备的干扰。
- 防火墙干扰: 防火墙可能会阻止或干扰 SSH 连接。
- 资源问题: 服务器资源不足时,也有可能出现无法成功进行密钥交换。
解决办法
以下是一些解决 "kex_exchange_identification: read: Connection reset by peer"
错误的方法,根据上述原因进行针对性的处理:
1. 检查客户端和服务端协议及加密算法兼容性
首先需要确认客户端和服务端都支持相同的密钥交换算法、加密算法以及消息认证码。 可以通过配置服务器端允许支持多重兼容性。服务端配置方式示例如下,以下代码会显示默认的 SSH 协议支持。如果必要,您可以根据需求配置更多具体的协议。
import org.apache.sshd.server.SshServer;
import org.apache.sshd.common.util.security.SecurityUtils;
import org.apache.sshd.common.kex.BuiltinDHFactories;
import org.apache.sshd.common.cipher.BuiltinCiphers;
import org.apache.sshd.common.mac.BuiltinMacs;
public class SshServerConfig {
public static void config(SshServer sshd){
sshd.setKeyExchangeFactories(BuiltinDHFactories.values());
sshd.setCipherFactories(BuiltinCiphers.values());
sshd.setMacFactories(BuiltinMacs.values());
SecurityUtils.getRegisteredProviders().forEach(provider -> {
System.out.println("Registered provider: "+provider.getName() );
});
sshd.getKexFactories().forEach(factory-> {
System.out.println("Kex algorithm support:"+factory.getName());
});
sshd.getCipherFactories().forEach(factory-> {
System.out.println("Cipher algorithm support:"+factory.getName());
});
sshd.getMacFactories().forEach(factory -> {
System.out.println("Mac algorithm support: "+ factory.getName());
});
}
}
-
操作步骤:
- 创建一个
SshServerConfig.java
文件,复制上面的代码。 - 在
start()
函数里,SshServerConfig.config(sshd);
即可显示默认的支持并配置SSH 服务端支持的算法。 - 观察输出结果,确认客户端和服务端协议是否兼容。
- 创建一个
2. 确保服务端密钥正确配置
服务端需要配置正确的 host key ,确保服务端能够验证自己。如果使用不匹配的 key 可能会导致 KEX 交换失败。 在问题中使用的代码如下已经做到了,确保服务端使用的 hostkey 是和服务器端文件系统里的 key 相匹配。
// If the host key does not exist yet, it will be auto-created
final File hostKey = new File(sshConfig.privateHostKey());
SimpleGeneratorHostKeyProvider hostKeyProvider = new SimpleGeneratorHostKeyProvider(hostKey.toPath());
hostKeyProvider.setAlgorithm(KeyUtils.RSA_ALGORITHM);
if (!hostKey.exists()) {
final List<KeyPair> hostKeys = hostKeyProvider.loadKeys(null);
if (!hostKeys.isEmpty()) {
Files.writeString(
new File(sshConfig.privateHostKey()).toPath(),
hostKeys.getFirst().getPrivate().toString()
);
Files.writeString(
new File(sshConfig.publicHostKey()).toPath(),
hostKeys.getFirst().getPublic().toString()
);
}
}
sshd.setKeyPairProvider(hostKeyProvider);
sshd.setHostKeyCertificateProvider(new FileHostKeyCertificateProvider(hostKey.toPath()));
- 操作步骤:
- 检查配置的私钥文件是否确实存在,路径是否正确。
- 检查 hostKey的公钥私钥是否匹配。
- 考虑重新生成新的密钥对,然后更新服务端配置。
ssh-keygen -t rsa -b 4096 -f ~/.ssh/my_ssh_host_key
ssh-keygen -y -f ~/.ssh/my_ssh_host_key > ~/.ssh/my_ssh_host_key.pub
将生成的 my_ssh_host_key
以及 my_ssh_host_key.pub
部署到应用。
3. 检查客户端配置
检查客户端配置确保它使用了正确的密钥进行连接。客户端可以使用 -v
参数查看具体协商信息, 也可以指定特定的加密算法进行连接测试。
ssh -vvv -i path_to_key -p 2222 <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="553431383c3b156467627b657b657b64">[email protected]</a> -oKexAlgorithms=diffie-hellman-group14-sha256
尝试更改不同的 -oKexAlgorithms=diffie-hellman-group14-sha256
, 可以尝试 diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512 这样的选项,进一步定位问题。如果连接成功,表明默认密钥交换算法服务端并没有正确支持,考虑第一点建议,更改服务端默认支持的算法。
- 操作步骤:
- 使用客户端命令,带
-v
参数查看调试输出信息 - 使用客户端
-oKexAlgorithms
选项指定特定算法。 - 如果必要,请检查
~/.ssh/config
文件。确保配置不会干扰到 SSH 连接。
- 使用客户端命令,带
4. 检查网络问题及防火墙配置
防火墙配置问题较为隐蔽。可以临时关闭防火墙, 看看问题是否还存在。 或者在防火墙配置里添加对于端口 2222
(默认值)允许通信的规则。网络配置不正确, 也可能会导致 connection reset, 需要仔细排查,比如网卡是否工作,网络协议配置,是否正确等。可以使用 ping 测试或者 telnet 测试服务端端口,查看网络是否可以访问,例如:
ping 127.0.0.1 # 如果本机IP不是 127.0.0.1 可以尝试ping 服务端IP地址
telnet 127.0.0.1 2222 # 如果本机IP不是 127.0.0.1 可以尝试telnet 服务端IP地址 以及SSH 监听的端口
- 操作步骤:
- 关闭防火墙进行测试,或者为SSH 服务打开指定端口,端口默认为2222。
- 使用 ping 或 telnet 测试服务端连接性。
5. 服务器资源排查
服务端应用需要充足的资源才能维持连接,如果服务器的内存,CPU 过低,可能会无法进行连接,导致错误,需要对服务器的资源进行排查,通过top命令,监控内存以及cpu等,必要时候需要升级资源,提高服务的稳定性和性能。
top
- 操作步骤:
- 执行top命令,查看服务资源使用情况,如果发现CPU和内存接近100% ,可能需要进行扩容。
附加的安全建议
- 限制访问: 确保只允许来自特定 IP 地址或 IP 地址范围的 SSH 连接。
- 使用密钥验证: 禁用密码认证,使用 SSH 密钥进行身份验证,增强安全性。
- 保持更新: 及时更新 Apache Mina SSHD 和其他相关组件,修复潜在的安全漏洞。
- 日志记录: 开启详细日志,以便更好地诊断和排查问题,尤其针对认证登录尝试。
- 使用监控: 可以使用监控系统来监视系统以及SSH服务运行状况。
总结
当面对 Apache Mina SSHD 中的 “kex_exchange_identification: read: Connection reset by peer
” 错误时,需要仔细检查协议兼容性、服务端密钥配置、客户端配置以及网络连接。 通过逐一排查,您应该能够有效地定位问题并解决它。在问题解决后,加强安全配置也非常必要,保证服务的安全稳定运行。