com.jcraft.jsch.JSchException:UnknownHostKey


177

我正在尝试使用Jsch在Java中建立SSH连接。我的代码产生以下异常:

com.jcraft.jsch.JSchException: UnknownHostKey: mywebsite.com. 
RSA key fingerprint is 22:fb:ee:fe:18:cd:aa:9a:9c:78:89:9f:b4:78:75:b4

我在Jsch文档中找不到如何验证主机密钥。我在下面包含了我的代码。

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;

public class ssh {
    public static void main(String[] arg) {

        try {
            JSch jsch = new JSch();

            //create SSH connection
            String host = "mywebsite.com";
            String user = "username";
            String password = "123456";

            Session session = jsch.getSession(user, host, 22);
            session.setPassword(password);
            session.connect();

        } catch(Exception e) {
            System.out.println(e);
        } 
    }
}

尝试关闭* nix主机上的sshd,并在前台启动一个线程:/ usr / sbin / sshd -d这将为您提供来自sshd端的大量调试信息。

@AmmSokun 每个人都能够解决此问题。查看答案。
bmargulies 2012年

Answers:


225

我会:

  1. 尝试ssh从命令行执行并接受公钥(主机将添加到主机~/.ssh/known_hosts,然后从Jsch开始一切正常)-或-
  2. 使用以下代码将JSch配置为不使用“ StrictHostKeyChecking”(这会引入不安全性,并且仅应用于测试目的):

    java.util.Properties config = new java.util.Properties(); 
    config.put("StrictHostKeyChecking", "no");
    session.setConfig(config);

选项#1(将主机添加到~/.ssh/known_hosts文件中)具有我的偏好。


37
JSch#setConfig("StrictHostKeyChecking", "no")会做同样的工作,但只是一行
而已

2
旁注:~/.ssh/config当我无权修改源代码时,我使用此反馈来配置文件以修复上述错误
Adam Rofer

您对.ssh / config做了什么?我有同样的错误。
伯纳德·伊吉里

19
这是不安全的,实际上不应该选择该原则作为正确答案。setKnownHosts()和setFingerPrint()选项是执行此操作的方法,而不会忽略ssh进程的重要方面。编辑:根据我的经验,#1在某些IDE环境(例如Eclipse)中无法正常工作。
Rondo

1
它在日食中为我完成了工作……正是我在测试环境中所需要的……
ProfVersaggi 2015年

46

虽然通常已经回答了该问题,但是我发现自己甚至在某些情况下,即使现有的known_hosts条目也无济于事。当SSH服务器发送ECDSA指纹时,会发生这种情况,结果,您将获得如下所示的条目:

|1|+HASH=|HASH= ecdsa-sha2-nistp256 FINGERPRINT=

问题是JSch 更喜欢 SHA_RSA,并且在连接时它将尝试比较SHA-RSA指纹,这将导致有关“未知主机”的错误。

要解决此问题,只需运行:

$ ssh-keyscan -H -t rsa example.org >> known_hosts

或向Jcraft抱怨宁愿使用SHA_RSA而不是使用本地HostKeyAlgorithms设置,尽管他们似乎并不急于修复其bug


1
在类似的情况下,使用ecdsa-sha2-nistp384和,您的解决方案效果很好。根据openssh-keyscan手册以及我们的需要,我们运行ssh-keyscan -t rsa,ecdsa example.org >> known_hosts
taringamberini

1
我遇到了这样的问题,但例外是JSchException:拒绝HostKey:而不是JSchException:UnknownHostKey(这可能对其他一些用户有所帮助)
bdulac

我还必须按照@krishnakumarp的建议添加setKnownHosts文件
Wolfgang Fahl,

34

避免检查主机密钥是安全隐患。

JSch使用HostKeyRepository接口及其默认实现KnownHosts类进行管理。您可以通过实现HostKeyRepository提供允许特定键的替代实现。或者,您可以将要允许的密钥保留在一个已知的主机格式的文件中,然后调用

jsch.setKnownHosts(knownHostsFileName);

或使用如下的公共密钥String。

String knownHostPublicKey = "mysite.com ecdsa-sha2-nistp256 AAAAE............/3vplY";
jsch.setKnownHosts(new ByteArrayInputStream(knownHostPublicKey.getBytes()));

有关更多详细信息,请参见Javadoc

这将是一个更安全的解决方案。

Jsch是开源的,您可以从此处下载源代码。在示例文件夹中,查找KnownHosts.java以了解更多详细信息。


16

根据您用于ssh的程序的不同,获取正确密钥的方法可能会有所不同。Putty(在Windows上很流行)使用自己的ssh密钥格式。对于我所见过的Linux和BSD的大多数变体,您只需要查看即可~/.ssh/known_hosts。我通常从Linux机器上使用ssh,然后将此文件复制到Windows机器上。然后我用类似的东西

jsch.setKnownHosts("C:\\Users\\cabbott\\known_hosts");

假设我已将文件C:\Users\cabbott放在Windows计算机上。如果您无权使用Linux计算机,请尝试 http://www.cygwin.com/

也许其他人可以建议其他Windows替代方案。我发现腻子通过将SSH密钥以非标准格式存储在注册表中来提取它们的方式来处理SSH密钥。


在使用ssh的Windows上cygwin(您必须下载openssl软件包和依赖项),我已经能够下载~/.ssh/known_hosts。感谢@CharityAbbott。
taringamberini 2015年

10

提供主机的公共RSA密钥:-

String knownHostPublicKey = "mywebsite.com ssh-rsa AAAAB3NzaC1.....XL4Jpmp/";

session.setKnownHosts(new ByteArrayInputStream(knownHostPublicKey.getBytes()));

1
不适用于jsch 0.1.50版(在jsch中始终具有NPE),但适用于最新版本0.1.53。
Udo 2015年

当Jsch代码(Util.byte2str())需要UTF-8编码时,此(String.getBytes())是否将提供一个由unicode编码的字符的字节数组?
富p

7

你也可以简单地做

session.setConfig("StrictHostKeyChecking", "no");

它不安全,并且是不适合实时环境的解决方法,因为它将禁用全局已知的主机密钥检查。


2
尽管此代码可以帮助回答问题,但仅代码的答案质量不高。更好的答案是解释代码的作用,告诉代码在哪里插入,解释为什么采用这种方法以及链接到相关文档。
Stephen Ostermiller 2014年

6

您还可以执行以下代码。它已经过测试并且可以正常工作。

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UIKeyboardInteractive;
import com.jcraft.jsch.UserInfo;

public class SFTPTest {

    public static void main(String[] args) {
        JSch jsch = new JSch();
        Session session = null;
        try {
            session = jsch.getSession("username", "mywebsite.com", 22); //default port is 22
            UserInfo ui = new MyUserInfo();
            session.setUserInfo(ui);
            session.setPassword("123456".getBytes());
            session.connect();
            Channel channel = session.openChannel("sftp");
            channel.connect();
            System.out.println("Connected");
        } catch (JSchException e) {
            e.printStackTrace(System.out);
        } catch (Exception e){
            e.printStackTrace(System.out);
        } finally{
            session.disconnect();
            System.out.println("Disconnected");
        }
    }

    public static class MyUserInfo implements UserInfo, UIKeyboardInteractive {

        @Override
        public String getPassphrase() {
            return null;
        }
        @Override
        public String getPassword() {
            return null;
        }
        @Override
        public boolean promptPassphrase(String arg0) {
            return false;
        }
        @Override
        public boolean promptPassword(String arg0) {
            return false;
        }
        @Override
        public boolean promptYesNo(String arg0) {
            return false;
        }
        @Override
        public void showMessage(String arg0) {
        }
        @Override
        public String[] promptKeyboardInteractive(String arg0, String arg1,
                String arg2, String[] arg3, boolean[] arg4) {
            return null;
        }
    }
}

请替换适当的值。


是的,我添加了该信息以供参考。我将删除它。谢谢。
Vishnu Prasad Kallummel

1
当连接到某些提供键盘交互式身份验证方法的SSH服务器时,这会导致某种奇怪的身份验证问题。我用了多年的时间来摆脱Key的问题,然后直到今天才被某个服务器烧掉。因为我没有通过getPassword()提供PW,而是直接提供给Session对象。记在脑子里。我不会再使用了。
Marc

1

只需替换“用户”,“通过”,“ SSHD_IP”即可。然后使用服务器的〜/ .ssh / known_hosts的内容创建一个名为known_hosts.txt的文件。您将获得一个外壳。

public class Known_Hosts {
public static void main(String[] arg) {
    try {
        JSch jsch = new JSch();
        jsch.setKnownHosts("known_hosts.txt");
        Session session = jsch.getSession("user", "SSHD_IP", 22);
        session.setPassword("pass");
        session.connect();
        Channel channel = session.openChannel("shell");
        channel.setInputStream(System.in);
        channel.setOutputStream(System.out);
        channel.connect();
    } catch (Exception e) {
        System.out.println(e);
    }
  }
}

不,对我不起作用。同样,如果我注释掉,Eric Leschinski / Rakesh Acharya的答案将失败config.put("StrictHostKeyChecking", "no"); 。手动ssh -v连接显示.ssh/known_hosts文件确实包含密钥(ecdsa-sha2-nistp256),但是代码这样做: com.jcraft.jsch.JSchException: UnknownHostKey: 131.132.x.x. RSA key fingerprint is c2:... at com.jcraft.jsch.Session.checkHost(Session.java:805) at com.jcraft.jsch.Session.connect(Session.java:345)
Urhixidur

已经有一段时间了,我会尝试使用2013年6月13日提供的JSCH库版本,因为此后库中的内容可能发生了变化
dalvarezmartinez1

1

设置已知主机比设置手指打印值更好。

设置已知主机时,请尝试从应用程序运行框中手动ssh(第一次,在应用程序运行之前)。


1

我在这个愚蠢的问题上浪费了很多时间,我认为消息很正确:“我正在访问的文件中没有主机”,但是您的系统上可以有一个more_host文件(例如正在使用mobaXterm,并且将其保留在从该根目录安装主目录的安装目录中。

如果您遇到的问题:它是从命令行运行的,但不是从应用程序构成的,请尝试使用ssh访问远程服务器,并使用verbose -v选项检查当前使用的文件示例,例如:

 ssh -v git@gitlab.com
 OpenSSH_6.2p2, OpenSSL 1.0.1g 7 Apr 2014
 debug1: Reading configuration data /etc/ssh_config
 debug1: Connecting to gitlab.com [104.210.2.228] port 22.
 debug1: Connection established.
 debug1: identity file /home/mobaxterm/.ssh/id_rsa type 1
 debug1: identity file /home/mobaxterm/.ssh/id_rsa-cert type -1
 debug1: identity file /home/mobaxterm/.ssh/id_dsa type -1
 debug1: identity file /home/mobaxterm/.ssh/id_dsa-cert type -1
 debug1: identity file /home/mobaxterm/.ssh/id_ecdsa type -1
 debug1: identity file /home/mobaxterm/.ssh/id_ecdsa-cert type -1
 debug1: Enabling compatibility mode for protocol 2.0
 debug1: Local version string SSH-2.0-OpenSSH_6.2
 debug1: Remote protocol version 2.0, remote software version OpenSSH_7.2p2      Ubuntu-4ubuntu2.1
 debug1: match: OpenSSH_7.2p2 Ubuntu-4ubuntu2.1 pat OpenSSH*
 debug1: SSH2_MSG_KEXINIT sent
 debug1: SSH2_MSG_KEXINIT received
 debug1: kex: server->client aes128-ctr hmac-sha1-etm@openssh.com zlib@openssh.com
 debug1: kex: client->server aes128-ctr hmac-sha1-etm@openssh.com zlib@openssh.com
 debug1: sending SSH2_MSG_KEX_ECDH_INIT
 debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
 debug1: Server host key: RSA b6:03:0e:39:97:9e:d0:e7:24:ce:a3:77:3e:01:42:09
 debug1: Host 'gitlab.com' is known and matches the RSA host key.
 debug1: Found key in /home/mobaxterm/.ssh/known_hosts:19
 debug1: ssh_rsa_verify: signature correct

如您所见,密钥位于:

debug1: Found key in /home/mobaxterm/.ssh/known_hosts:19

而不是在我的Windows主目录下的C:\ Users \ my_local_user下 \ .ssh目录下,我只是将它们合并并对齐以解决问题。

希望这对以后的人有所帮助


0

有人能解决这个问题吗?我正在使用Jscp使用公共密钥身份验证来scp文件(我不想使用密码身份验证)。帮助将不胜感激!!!

此stackoverflow条目与主机密钥检查有关,与公钥身份验证无关。

至于公钥身份验证,请尝试将以下示例与您的普通(非加密)私钥一起使用,


0
JSch jsch = new JSch();
Session session = null;
try {
session = jsch.getSession("user", "hostname", 22); // default
UserInfo ui = new MyUserInfo();
session.setUserInfo(ui);
session.setPassword("password".getBytes());
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
Channel channel = session.openChannel("sftp");
channel.connect();
System.out.println("Connected");
} catch (JSchException e) {
e.printStackTrace(System.out);
} catch (Exception e) {
e.printStackTrace(System.out);
} finally {
session.disconnect();
System.out.println("Disconnected");
}
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.