java - "The Transport Protocol thread failed"– "The socket is EOF"使用 Java 与 J2SSH 连接

标签 java ssh ssh-keys j2ssh

我正在尝试通过我的 Java 代码建立 SSH 连接,但遇到异常。我通过 Putty/Winscp 工具测试了我的连接,它工作正常。问题出在我的 Java 代码上......

SEVERE: The Transport Protocol thread failed
java.io.IOException: The socket is EOF
    at com.sshtools.j2ssh.transport.TransportProtocolInputStream.readBufferedData(Unknown Source)
    at com.sshtools.j2ssh.transport.TransportProtocolInputStream.readMessage(Unknown Source)
    at com.sshtools.j2ssh.transport.TransportProtocolCommon.readMessage(Unknown Source)
    at com.sshtools.j2ssh.transport.kex.DhGroup1Sha1.performClientExchange(Unknown Source)
    at com.sshtools.j2ssh.transport.TransportProtocolClient.performKeyExchange(Unknown Source)
    at com.sshtools.j2ssh.transport.TransportProtocolCommon.beginKeyExchange(Unknown Source)
    at com.sshtools.j2ssh.transport.TransportProtocolCommon.onMsgKexInit(Unknown Source)
    at com.sshtools.j2ssh.transport.TransportProtocolCommon.startBinaryPacketProtocol(Unknown Source)
    at com.sshtools.j2ssh.transport.TransportProtocolCommon.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

下面是我建立连接的一段Java代码

public class MySSHClient {

  static SshClient ssh = null;
  static SshConnectionProperties properties = null;
  SessionChannelClient session = null;

  private static void MySSHClient(String hostName, String userName, String passwd )
  {

    try
    {
      // Make a client connection
      ssh = new SshClient();
      properties = new SshConnectionProperties();
      properties.setHost("192.168.1.175");

      // Connect to the host
      ssh.connect(properties, new IgnoreHostKeyVerification());

      // Create a password authentication instance
      PasswordAuthenticationClient pwd = new PasswordAuthenticationClient();

      pwd.setUsername("root");
      pwd.setPassword("123456");

      // Try the authentication
      int result = ssh.authenticate(pwd);

      // Evaluate the result
      if (result==AuthenticationProtocolState.COMPLETE) {

        System.out.println("Connection Authenticated");
      }
    }
    catch(Exception e)
    {
      System.out.println("Exception : " + e.getMessage());
    }

  }//end of method.


  public String execCmd(String cmd)
  {
    String theOutput = "";
    try
    {
      // The connection is authenticated we can now do some real work!
      session = ssh.openSessionChannel();

      if ( session.executeCommand(cmd) )
      {
        IOStreamConnector output = new IOStreamConnector();
        java.io.ByteArrayOutputStream bos =  new
        java.io.ByteArrayOutputStream();
        output.connect(session.getInputStream(), bos );
        session.getState().waitForState(ChannelState.CHANNEL_CLOSED);
        theOutput = bos.toString();
      }
      //else
      //throw Exception("Failed to execute command : " + cmd);
      //System.out.println("Failed to execute command : " + cmd);
    }
    catch(Exception e)
    {
      System.out.println("Exception : " + e.getMessage());
    }

    return theOutput;
  }

  public static void main(String[] args){
      MySSHClient(null, null, null);
    }

最佳答案

动机

我在调查问题 java.io.IOException: The socket is EOF 中的错误时偶然发现了这个问题和答案。因为在我的情况下无法立即更改代码以使用其他一些 SSH Java 库,而且 @a3.14_Infinity 的说明对我来说不够详细,所以我想补充一下我的看法。

java.io.IOException:套接字为 EOF - 为什么?

因为这个异常不是很有帮助,所以我首先尝试了Wireshark看看电线上发生了什么,但无济于事。所以我配置了 sshd_config (OpenSSH 6.9) 以登录 DEBUG3 级别并在 /var/log/auth.log 文件中得到了答案我的测试机。它在尝试与 SSH 客户端(Java SSH 库)协商 key 交换算法时报告了一个 fatal error

由于 SSH 服务器和客户端无法就相互 key 交换算法达成一致,OpenSSH 服务器终止了与客户端的连接。结果,Java SSH 库代码抛出异常。

但为什么会这样呢?

sshtools.j2ssh ( sshtools : j2ssh-core : 0.2.9 ) 库代码很旧并且已停产。以 OpenSSH 6.7 开头(2014 年 10 月发布)默认密码和 MAC 已更改以删除不安全的算法,其中包括 blowfish-cbc 密码。和 OpenSSH 6.9 (2015 年 6 月发布)默认禁用对 1024 位 diffie-hellman-group1-sha1 key 交换的支持。

当您仍然使用史前 SSH 工具 j2ssh 库(上帝保佑)连接到较新的 OpenSSH 服务器时,您将收到所描述的错误。该库代码仅向 OpenSSH 服务器提供 diffie-hellman-group1-sha1 key 交换算法,默认情况下不支持该算法。因此,无法建立安全连接。

无法更改代码?

如果不能立即转移到另一个 Java SSH 库(我的情况),那么您可以在 OpenSSH 的服务器配置文件中重新启用已禁用的 diffie-hellman-group1-sha1 key 交换算法 sshd_config。例如像这样。

Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,chacha20-poly1305@openssh.com,blowfish-cbc

KexAlgorithms diffie-hellman-group1-sha1,diffie-hellman-group-exchange-sha1,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 key 交换算法以及 blowfish-cbc 密码默认情况下处于关闭状态,因为它们不安全。在您可以替换这个过时的 Java SSH 库之前,重新启用它们应该只是一个临时措施。

最后,我想指出其他答案中建议的 Java 安全通道 (JSch) 库已停止使用。因此,您可能需要考虑 sshj甚至 ssh2j-maverick相反。

编辑:我错了Java 安全通道 JSch 库还活着(JSCH 0.1.54 于 2016-09-03 on MavenCentral 发布),当然值得您考虑。或者,您可能还想考虑 sshjssh2j-maverick .

附录:迁移

为了尽量减少 sshtools.j2ssh ( sshtools : j2ssh-core : 0.2.9 ) 库的迁移工作,我查看了commercial 遗留 SSH 客户端库来自 SSHTOOLS (版本 1.7.1)。这允许保留现有的库集成代码,对库 API 和异常处理进行少量更改。因此,如果您不想从头开始,那么硬着头皮坚持使用 SSHTOOLS 可能是您的最佳选择。最后,为了评估迁移工作,我首先用 SSHTOOLS 的开源库替换了库 ssh2j-maverick其最新商业版本(版本 1.7.1)几乎具有相同的 API。

关于java - "The Transport Protocol thread failed"– "The socket is EOF"使用 Java 与 J2SSH 连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35307393/

相关文章:

java - 无法使用 Postman : USER_REQUIRED error 在 reddit 上发表评论

java - 不是封闭类错误 Android Studio

java - Jsoup Java 获取特定的td

macos - SCP 说文件已下载,但文件未出现

ssh - 在关闭 ssh 连接之前一致执行命令

Java根据条件计算计数

ssl - 如何在 SSH 隧道中忽略主机名

git clone 不询问用户密码

ruby-on-rails - 尝试设置 .SSH key 以通过 Cygwin 连接到 Github

Git 克隆失败 - 致命 : The remote end hung up unexpectedly. 致命:早期 EOF 致命:索引包失败