com.jcraft.jsch.JSchException: UnknownHostKey

179

Próbuję użyć Jsch do ustanowienia połączenia SSH w Javie. Mój kod generuje następujący wyjątek:

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

Nie mogę znaleźć sposobu weryfikacji klucza hosta w dokumentacji Jsch. Poniżej zamieściłem mój kod.

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);
        } 
    }
}
Alex
źródło
Spróbuj zamknąć sshd na swoim hoście * nix i uruchom pojedynczy wątek na pierwszym planie: / usr / sbin / sshd -d To da ci wiele informacji o debugowaniu po stronie sshd.
@AmmSokun każdy był w stanie rozwiązać ten problem. Zobacz odpowiedzi.
bmargulies

Odpowiedzi:

226

Chciałbym:

  1. Spróbuj sshz wiersza poleceń i zaakceptuj klucz publiczny (host zostanie dodany ~/.ssh/known_hostsi wszystko powinno działać dobrze z Jsch) -LUB-
  2. Skonfiguruj JSch tak, aby nie używał „StrictHostKeyChecking” (wprowadza to niepewność i powinno być używane tylko do celów testowych), używając następującego kodu:

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

Opcja nr 1 (dodanie hosta do ~/.ssh/known_hostspliku) ma moje preferencje.

Pascal Thivent
źródło
37
JSch#setConfig("StrictHostKeyChecking", "no")wykona tę samą pracę, ale tylko w jednej linii
yegor256
2
Uwaga dodatkowa: wykorzystałem tę opinię, aby skonfigurować mój ~/.ssh/configplik, aby naprawić powyższy błąd, gdy nie miałem dostępu do modyfikacji kodu źródłowego
Adam Rofer
Co zrobiłeś ze swoim .ssh / config? Mam ten sam błąd.
Bernard Igiri,
19
Jest to niepewne i naprawdę nie powinno być wybrane jako właściwa odpowiedź na tej zasadzie. Opcje setKnownHosts () i setFingerPrint () pozwalają to zrobić bez ignorowania ważnego aspektu procesu ssh. Edycja: z mojego doświadczenia wynika, że ​​numer 1 nie działa w niektórych środowiskach IDE, takich jak Eclipse.
Rondo,
1
Wykonało
46

Chociaż udzielono ogólnej odpowiedzi na pytanie, stwierdziłem, że jest przypadek, w którym nawet istniejący wpis known_hosts nie pomaga. Dzieje się tak, gdy serwer SSH wysyła odcisk palca ECDSA, w wyniku czego otrzymasz taki wpis:

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

Problem w tym, że JSch preferuje SHA_RSA i podczas łączenia spróbuje porównać odcisk palca SHA-RSA, co zakończy się błędem o "nieznanym hoście".

Aby to naprawić, po prostu uruchom:

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

lub narzekać na Jcraft, że preferuje SHA_RSA zamiast używania lokalnego ustawienia HostKeyAlgorithms , chociaż nie wydaje się, aby byli zbyt chętni do naprawiania swoich błędów .

kszatan
źródło
1
Jesteśmy w podobnym przypadku ecdsa-sha2-nistp384, a Twoje rozwiązanie działa bardzo dobrze. Zgodnie z instrukcją openssh-keyscan i naszymi potrzebami, uruchamiamy ssh-keyscan -t rsa,ecdsa example.org >> known_hosts.
taringamberini
1
Miałem taki problem, ale wyjątkiem był JSchException: odrzucenie HostKey: zamiast JSchException: UnknownHostKey (może to pomóc niektórym innym użytkownikom)
bdulac
Musiałem dodatkowo dodać plik setKnownHosts zgodnie z propozycją @krishnakumarp
Wolfgang Fahl
34

Unikanie sprawdzania klucza hosta stanowi zagrożenie bezpieczeństwa.

JSch używa interfejsu HostKeyRepository i jego domyślnej implementacji klasy KnownHosts do zarządzania tym. Możesz zapewnić alternatywną implementację, która zezwala na określone klucze, implementując HostKeyRepository. Lub możesz zachować klucze, które chcesz zezwolić, w pliku w formacie znane_hosty i wywołać

jsch.setKnownHosts(knownHostsFileName);

Lub z ciągiem klucza publicznego, jak poniżej.

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

zobacz Javadoc, aby uzyskać więcej informacji.

Byłoby to bezpieczniejsze rozwiązanie.

Jsch jest oprogramowaniem typu open source i możesz pobrać źródło stąd . W folderze z przykładami poszukaj KnownHosts.java, aby poznać więcej szczegółów.

krishnakumarp
źródło
16

W zależności od programu używanego do ssh, sposób uzyskania właściwego klucza może się różnić. Putty (popularny w systemie Windows) używa własnego formatu kluczy ssh. W przypadku większości wariantów Linuksa i BSD, które widziałem, wystarczy zajrzeć ~/.ssh/known_hosts. Zwykle ssh z komputera z systemem Linux, a następnie kopiuję ten plik na komputer z systemem Windows. Następnie używam czegoś podobnego do

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

Zakładając, że umieściłem plik C:\Users\cabbottna moim komputerze z systemem Windows. Jeśli nie masz dostępu do komputera z systemem Linux, spróbuj http://www.cygwin.com/

Może ktoś inny zasugeruje inną alternatywę dla systemu Windows. Uważam, że sposób obsługi kluczy SSH przez putty poprzez przechowywanie ich w rejestrze w niestandardowym formacie jest kłopotliwy do wyodrębnienia.

Charity Leschinski
źródło
W systemie Windows przy użyciu ssh w cygwin(musisz pobrać opensslpakiet i zależności) udało mi się pobrać ~/.ssh/known_hosts. Dzięki @CharityAbbott.
taringamberini
10

Podaj publiczny klucz rsa hosta: -

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

session.setKnownHosts(new ByteArrayInputStream(knownHostPublicKey.getBytes()));
Mark Beer
źródło
1
Nie działało dla mnie z wersją jsch 0.1.50 (zawsze miał NPE w jsch), ale z najnowszą wersją 0.1.53 działa.
Udo,
Czy this (String.getBytes ()) zapewni tablicę bajtów zawierającą znaki zakodowane w formacie Unicode, gdy kod Jsch (Util.byte2str ()) oczekuje kodowania UTF-8?
bogaty p
7

Możesz też po prostu to zrobić

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

Nie jest to bezpieczne i jest obejściem, które nie jest odpowiednie dla środowiska na żywo, ponieważ spowoduje wyłączenie sprawdzania kluczy hostów znanych na całym świecie.

Amaury D.
źródło
2
Chociaż ten kod może pomóc odpowiedzieć na pytanie, same odpowiedzi nie są wysokiej jakości. Lepsza odpowiedź wyjaśniałaby, co robi kod, wskazywałaby, gdzie go wstawić, wyjaśniałaby, dlaczego przyjęto takie podejście, i zawierałaby link do odpowiedniej dokumentacji.
Stephen Ostermiller
6

Możesz również wykonać następujący kod. Jest przetestowany i działa.

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

Proszę podstawić odpowiednie wartości.

Vishnu Prasad Kallummel
źródło
Tak, dodałem to w celach informacyjnych. Usunę to. Dzięki.
Vishnu Prasad Kallummel
1
spowodowało to dziwne problemy z uwierzytelnianiem podczas łączenia się z niektórymi serwerami SSH oferującymi interaktywną metodę uwierzytelniania za pomocą klawiatury. Używałem go przez lata, aby pozbyć się klucza, a potem właśnie dzisiaj zostałem spalony przez pewien serwer. Ponieważ nie dostarczyłem PW przez getPassword (), ale bezpośrednio do obiektu Session. Miej to w pamięci. Już bym go nie używał.
Marc
1

Wystarczy podstawić „użytkownik”, „przepustka”, „SSHD_IP”. I stwórz plik o nazwie known_hosts.txt z zawartością ~ / .ssh / known_hosts serwera. Otrzymasz muszlę.

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);
    }
  }
}
dalvarezmartinez1
źródło
Nie działa na mnie. Podobnie odpowiedź Erica Leschinskiego / Rakesh Acharya zawodzi, jeśli skomentuję config.put("StrictHostKeyChecking", "no"); . Ręczne ssh -vpołączenie ujawnia, że .ssh/known_hostsplik zawiera klucz ( ecdsa-sha2-nistp256), ale kod robi to: 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
Minęło trochę czasu, co chciałbym zrobić, to użyć wersji biblioteki JSCH dostępnej 13 czerwca 2013, ponieważ od tego czasu rzeczy prawdopodobnie się zmieniły w bibliotece
dalvarezmartinez1
1

ustawienie znanego hosta jest lepsze niż ustawienie wartości wydruku palca.

Po ustawieniu znanego hosta spróbuj ręcznie ssh (za pierwszym razem, przed uruchomieniem aplikacji) z pola, w którym działa aplikacja.

sreenath V
źródło
1

Straciłem dużo czasu na tym głupim problemie i myślę, że wiadomość jest całkiem poprawna „w pliku, do którego uzyskuję dostęp nie ma hosta”, ale możesz mieć więcej niż plik know_host w swoim systemie (na przykład i Używam mobaXterm i zachowuje swój własny w katalogu instalacyjnym, montując dom z tego katalogu głównego).

Jeśli doświadczasz: działa z wiersza poleceń, ale nie z poziomu aplikacji, spróbuj uzyskać dostęp do zdalnego serwera za pomocą ssh i sprawdź za pomocą opcji verbose -v, który plik jest obecnie używany, przykład poniżej:

 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

jak widać klucz został znaleziony w:

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

a nie w moim domu Windows w C: \ Users \ my_local_user \ .ssh, po prostu połączyłem je i wyrównałem, aby rozwiązać problem.

Mam nadzieję, że to pomoże komuś w przyszłości

loreii
źródło
0

Czy ktoś był w stanie rozwiązać ten problem? Używam Jscp do plików scp przy użyciu uwierzytelniania za pomocą klucza publicznego (nie chcę używać uwierzytelniania za pomocą hasła). Pomoc zostanie doceniona !!!

Ten wpis stackoverflow dotyczy sprawdzania klucza hosta i nie ma związku z uwierzytelnianiem za pomocą klucza publicznego.

Jeśli chodzi o uwierzytelnianie za pomocą klucza publicznego, wypróbuj poniższy przykład ze zwykłym (niezaszyfrowanym) kluczem prywatnym,

ymnk
źródło
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");
}
}
Rakesh Acharya
źródło