com.jcraft.jsch.JSchException: UnknownHostKey


179

Sto cercando di utilizzare Jsch per stabilire una connessione SSH in Java. Il mio codice produce la seguente eccezione:

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

Non riesco a trovare come verificare la chiave host nella documentazione di Jsch. Ho incluso il mio codice qui sotto.

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);
        } 
    }
}

Prova a chiudere sshd sul tuo host * nix e avvia un singolo thread in primo piano: / usr / sbin / sshd -d Questo ti darà molte informazioni di debug dal lato sshd.

@AmmSokun tutti sono stati in grado di risolvere questo problema. Vedi le risposte
— bmargulies,

Risposte:


226

Vorrei:

  1. Provate sshdalla riga di comando e accettate la chiave pubblica (l'host verrà aggiunto ~/.ssh/known_hostse tutto dovrebbe funzionare correttamente da Jsch) -OPPURE-
  2. Configurare JSch in modo che non utilizzi "StrictHostKeyChecking" (questo introduce insicurezze e dovrebbe essere usato solo a scopo di test), usando il seguente codice:

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

L'opzione n. 1 (aggiunta dell'host al ~/.ssh/known_hostsfile) ha le mie preferenze.


37
JSch#setConfig("StrictHostKeyChecking", "no")farà lo stesso lavoro, ma in una sola riga
— yegor256

2
Nota a margine: ho usato questo feedback per configurare il mio ~/.ssh/configfile per correggere l'errore sopra quando non avevo accesso a modificare il codice sorgente
— Adam Rofer

Cosa hai fatto al tuo .ssh / config? Sto riscontrando lo stesso errore.
— Bernard Igiri,

19
Questo è insicuro e in realtà non avrebbe dovuto essere selezionato come la risposta giusta su quel principio. Le opzioni setKnownHosts () e setFingerPrint () sono il modo per farlo senza ignorare un aspetto importante del processo ssh. Modifica: nella mia esperienza, # 1 non funziona all'interno di alcuni ambienti IDE come Eclipse.
— Rondo,

1
Ha fatto il lavoro per me all'interno di Eclipse ... proprio quello di cui avevo bisogno in un ambiente di test ....
— ProfVersaggi

46

Mentre alla domanda è stata data una risposta in generale, mi sono trovato che esiste un caso in cui anche la voce known_hosts esistente non aiuta. Questo accade quando un server SSH invia l'impronta digitale ECDSA e, di conseguenza, avrai una voce come questa:

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

Il problema è che JSch preferisce SHA_RSA e durante la connessione proverà a confrontare l'impronta digitale SHA-RSA, che si tradurrà in un errore su "host sconosciuto".

Per risolvere questo problema, esegui semplicemente:

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

o lamentarsi con Jcraft per preferire SHA_RSA invece di utilizzare l' impostazione HostKeyAlgorithms locale , anche se non sembrano troppo desiderosi di correggere i loro bug .


1
Siamo in un caso simile, con ecdsa-sha2-nistp384, e la tua soluzione funziona molto bene. In accordo con il manuale di openssh-keyscan e le nostre necessità, corriamo ssh-keyscan -t rsa,ecdsa example.org >> known_hosts.
— taringamberini

1
Ho avuto un tale problema, ma l'eccezione era JSchException: rifiutare HostKey: invece di JSchException: UnknownHostKey (questo potrebbe aiutare alcuni altri utenti)
— bdulac

Ho dovuto aggiungere anche il file setKnownHosts come proposto da @krishnakumarp
— Wolfgang Fahl

34

È un rischio per la sicurezza evitare il controllo della chiave host.

JSch utilizza l'interfaccia HostKeyRepository e la sua classe KnownHosts di implementazione predefinita per gestirlo. È possibile fornire un'implementazione alternativa che consenta chiavi specifiche implementando HostKeyRepository. In alternativa, è possibile conservare le chiavi che si desidera consentire in un file nel formato known_hosts e chiamare

jsch.setKnownHosts(knownHostsFileName);

O con una chiave pubblica String come di seguito.

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

vedi Javadoc per maggiori dettagli.

Questa sarebbe una soluzione più sicura.

Jsch è open source e puoi scaricare la fonte da qui . Nella cartella degli esempi, cerca KnownHosts.java per conoscere maggiori dettagli.


16

A seconda del programma utilizzato per ssh, il modo di ottenere la chiave corretta potrebbe variare. Putty (popolare con Windows) usa il proprio formato per i tasti ssh. Con la maggior parte delle varianti di Linux e BSD che ho visto, devi solo dare un'occhiata ~/.ssh/known_hosts. Di solito ssh da una macchina Linux e quindi copio questo file su una macchina Windows. Quindi uso qualcosa di simile a

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

Supponendo di aver inserito il file C:\Users\cabbottsul mio computer Windows. Se non si ha accesso a una macchina Linux, provare http://www.cygwin.com/

Forse qualcun altro può suggerire un'altra alternativa a Windows. Trovo che il modo di putty di gestire le chiavi SSH memorizzandole nel registro in un formato non standard sia fastidioso da estrarre.


Su windows usando h ssh in cygwin(devi scaricare il opensslpacchetto e le dipendenze) sono stato in grado di scaricare ~/.ssh/known_hosts. Grazie a @CharityAbbott.
— Taringamberini,

10

Fornire la chiave rsa pubblica dell'host: -

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

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

1
Non ha funzionato per me con la versione 0.1.50 di jsch (sempre ottenuto un NPE in jsch) ma con la versione 0.1.53 più recente funziona.
— Udo,

questo (String.getBytes ()) fornirà un array di byte di caratteri codificati unicode, quando il codice Jsch (Util.byte2str ()) prevede la codifica UTF-8?
— ricco p

7

Puoi anche semplicemente fare

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

Non è sicuro ed è una soluzione alternativa non adatta all'ambiente live poiché disabiliterà il controllo delle chiavi host conosciute a livello globale.


2
Mentre questo codice può aiutare a rispondere alla domanda, solo le risposte al codice non sono di alta qualità. Una risposta migliore spiegherebbe cosa fa il codice, dire dove inserirlo, spiegare perché questo approccio è stato adottato e collegarsi alla documentazione pertinente.
— Stephen Ostermiller,

6

Puoi anche eseguire il seguente codice. È testato e funzionante.

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;
        }
    }
}

Si prega di sostituire i valori appropriati.


Sì, l'avevo aggiunto come riferimento. Lo rimuoverò. Grazie.
— Vishnu Prasad Kallummel,

1
questo ha creato una sorta di strani problemi di autenticazione durante la connessione a determinati server SSH che offrono un metodo di autenticazione interattivo da tastiera. L'ho usato per anni per sbarazzarmi della cosa chiave e poi sono stato bruciato proprio oggi con un determinato server. Perché non ho fornito la PW tramite getPassword () ma direttamente all'oggetto Session. Tienilo a mente. Non lo userei più.
— Marc

1

Basta sostituire "user", "pass", "SSHD_IP". E crea un file chiamato known_hosts.txt con il contenuto del ~ / .ssh / known_hosts del server. Otterrai una conchiglia.

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);
    }
  }
}

No, non funziona per me. Allo stesso modo, la risposta di Eric Leschinski / Rakesh Acharya fallisce se commento config.put("StrictHostKeyChecking", "no"); Una ssh -vconnessione manuale rivela che il .ssh/known_hostsfile contiene la chiave ( ecdsa-sha2-nistp256) ma il codice fa questo: 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,

È passato un po 'di tempo, quello che proverei a fare, è usare la versione della libreria JSCH disponibile il 13 giugno 2013, perché le cose probabilmente sono cambiate nella libreria da allora
— dalvarezmartinez1

1

l'impostazione dell'host noto è meglio dell'impostazione del valore di stampa fingure.

Quando si imposta l'host noto, provare a ssh manualmente (la prima volta prima dell'esecuzione dell'applicazione) dalla casella in cui viene eseguita l'applicazione.


1

Ho perso molto tempo su questo stupido problema e penso che il messaggio sia corretto "non c'è l'host nel file a cui sto accedendo" ma puoi avere più di un file know_host in giro sul tuo sistema (come esempio sto usando mobaXterm e lo mantiene nella directory di installazione montando la home da quel root).

Se si verifica: funziona dalla riga di comando ma non dall'applicazione provare ad accedere al server remoto con ssh e verificare con l'opzione -v dettagliata quale file è attualmente utilizzato un esempio seguente:

 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

come puoi vedere la chiave è stata trovata in:

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

e non nella mia finestra di Windows sotto C: \ Users \ my_local_user \ .ssh, li ho semplicemente uniti e allineati per risolvere il problema.

Spero che questo aiuti qualcuno in futuro


0

Qualcuno è stato in grado di risolvere questo problema? Sto usando Jscp per scp i file usando l'autenticazione con chiave pubblica (non voglio usare l'autenticazione con password). L'aiuto sarà apprezzato !!!

Questa voce dello stackover riguarda il controllo della chiave host e non esiste alcuna relazione con l'autenticazione della chiave pubblica.

Per quanto riguarda l'autenticazione con chiave pubblica, prova il seguente esempio con la tua chiave privata semplice (non crittografata),


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");
}
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.