com.jcraft.jsch.JSchException: UnknownHostKey

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

com.jcraft.jsch.JSchException: UnknownHostKey: mywebsite.example.
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.example";
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);
}
}
}
234552 次浏览

我会:

  1. 尝试从命令行ssh并接受公钥(主机将被添加到~/.ssh/known_hosts,然后从Jsch一切都将正常工作)或者,
  2. 配置JSch不使用"StrictHostKeyChecking"(这会带来不安全,应该只用于测试目的),使用以下代码:

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

Option #1 (adding the host to the ~/.ssh/known_hosts file) has my preference.

避免主机密钥检查存在安全风险。

JSch使用HostKeyRepository接口和它的默认实现KnownHosts类来管理它。您可以通过实现HostKeyRepository提供允许特定密钥的替代实现。或者你可以将你想要允许的键保存在known_hosts格式中的文件中并调用

jsch.setKnownHosts(knownHostsFileName);

或使用公钥字符串,如下所示。

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

更多细节见Javadoc

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

Jsch是开源的,你可以从在这里下载源代码。在examples文件夹中,查找KnownHosts.java以了解更多细节。

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

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

假设我已经将文件放在Windows机器的C:\Users\cabbott中。如果你没有Linux机器,试试http://www.cygwin.com/

也许其他人可以建议另一种Windows替代方案。我发现putty处理SSH密钥的方法是将它们以非标准格式存储在注册表中,难以提取。

有人能解决这个问题吗?我正在使用Jscp来scp文件使用公钥 认证(我不想使用密码认证)。感谢你的帮助!!< / p >

该stackoverflow表项主要用于检查主机密钥,与公钥认证无关。

至于公钥身份验证,请使用普通(非加密)私钥尝试下面的示例

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

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.example", 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;
}
}
}

请代入适当的值。

设置已知主机比设置指纹值更好。

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

只需替换“user”,“pass”,“SSHD_IP”。并使用服务器的~/.ssh/known_hosts. txt文件创建一个名为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);
}
}
}
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");
}

你也可以简单地做

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

这是不安全的,它是一个不适合现场环境的解决方案,因为它将禁用全局已知的主机密钥检查。

提供主机的rsa公钥:—

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


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

我在这个愚蠢的问题上浪费了很多时间,我认为消息是非常正确的“在我正在访问的文件中没有主机”,但你可以在你的系统上有更多的know_host文件(例如,我使用mobaXterm,它保持它自己在安装目录中从根挂载home)。

如果你遇到:它从命令行工作,而不是从应用程序尝试访问您的远程服务器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 home下c:\ users \ __abc0 \。SSH,我只是将它们合并并对齐以解决问题。

希望这对将来的人有所帮助

虽然这个问题已经得到了一般的回答,但我发现自己存在一个情况下,即使现有的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设置,尽管他们似乎并不太急切的来修复他们的错误

我在@Jairo马丁内斯写的一个被删除的答案中找到了解决方案

首先,服务器需要将主机存储为哈希rsa

ssh-keyscan -H -t rsa SERVER_IP_ADDRESS >known_hosts_file

此外,还需要告诉Jsch主机密钥是散列的

session.setConfig(“HashKnownHosts",“yes");