com.jcraft.jsch.JSchException: UnknownHostKey

179

Estoy tratando de usar Jsch para establecer una conexión SSH en Java. Mi código produce la siguiente excepción:

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

No puedo encontrar cómo verificar la clave de host en la documentación de Jsch. He incluido mi código a continuación.

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
fuente
Intente apagar sshd en su host * nix e inicie un solo subproceso en primer plano: / usr / sbin / sshd -d Esto le dará mucha información de depuración desde el lado sshd.
@AmmSokun todos han podido resolver este problema. Ver las respuestas
bmargulies

Respuestas:

226

Yo tampoco:

  1. Intente sshdesde la línea de comandos y acepte la clave pública (el host se agregará ~/.ssh/known_hostsy todo debería funcionar bien desde Jsch) -O BIEN-
  2. Configure JSch para que no use "StrictHostKeyChecking" (esto introduce inseguridades y solo debe usarse con fines de prueba), utilizando el siguiente código:

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

La opción n. ° 1 (agregar el host al ~/.ssh/known_hostsarchivo) tiene mi preferencia.

Pascal Thivent
fuente
37
JSch#setConfig("StrictHostKeyChecking", "no")hará el mismo trabajo, pero en una sola línea
yegor256
2
Nota al margen: utilicé estos comentarios para configurar mi ~/.ssh/configarchivo para corregir el error anterior cuando no tuve acceso para modificar el código fuente
Adam Rofer
¿Qué le hiciste a tu .ssh / config? Estoy teniendo el mismo error
Bernard Igiri
19
Esto es inseguro y realmente no debería haber sido seleccionado como la respuesta correcta sobre ese principio. Las opciones setKnownHosts () y setFingerPrint () son la forma de hacerlo sin ignorar un aspecto importante del proceso ssh. Editar: en mi experiencia, el # 1 no funciona desde algunos entornos IDE como Eclipse.
Rondo
1
Hizo el trabajo para mí dentro del eclipse ... justo lo que necesitaba en un entorno de prueba ...
ProfVersaggi
46

Si bien la pregunta ha sido respondida en general, me he dado cuenta de que hay un caso en el que incluso la entrada existente de unknown_hosts no ayuda. Esto sucede cuando un servidor SSH envía una huella digital ECDSA y, como resultado, tendrá una entrada como esta:

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

El problema es que JSch prefiere SHA_RSA y, mientras se conecta, intentará comparar la huella digital SHA-RSA, lo que dará como resultado un error sobre "host desconocido".

Para solucionar esto, simplemente ejecute:

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

o quejarse con Jcraft acerca de preferir SHA_RSA en lugar de usar la configuración local HostKeyAlgorithms , aunque no parecen estar demasiado ansiosos por corregir sus errores .

kszatan
fuente
1
Estamos en un caso similar, con ecdsa-sha2-nistp384, y su solución funciona muy bien. De acuerdo con el manual openssh-keyscan , y nuestra necesidad, corremos ssh-keyscan -t rsa,ecdsa example.org >> known_hosts.
taringamberini
1
Tuve ese problema, pero la excepción fue JSchException: rechazar HostKey: en lugar de JSchException: UnknownHostKey (esto podría ayudar a otros usuarios)
bdulac
Además, tuve que agregar el archivo setKnownHosts propuesto por @krishnakumarp
Wolfgang Fahl
34

Es un riesgo de seguridad evitar la comprobación de la clave del host.

JSch utiliza la interfaz HostKeyRepository y su clase de implementación predeterminada KnownHosts para administrar esto. Puede proporcionar una implementación alternativa que permita claves específicas mediante la implementación de HostKeyRepository. O puede mantener las claves que desea permitir en un archivo en el formato conocido_hosts y llamar

jsch.setKnownHosts(knownHostsFileName);

O con una cadena de clave pública como se muestra a continuación.

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

ver Javadoc para más detalles.

Esta sería una solución más segura.

Jsch es de código abierto y puede descargar la fuente desde aquí . En la carpeta de ejemplos, busque KnownHosts.java para conocer más detalles.

krishnakumarp
fuente
16

Dependiendo del programa que use para ssh, la forma de obtener la clave adecuada podría variar. Putty (popular entre Windows) usa su propio formato para claves ssh. Con la mayoría de las variantes de Linux y BSD que he visto, solo tienes que buscar ~/.ssh/known_hosts. Por lo general, ssh desde una máquina Linux y luego copio este archivo a una máquina Windows. Entonces uso algo similar a

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

Suponiendo que he colocado el archivo en C:\Users\cabbottmi máquina Windows. Si no tiene acceso a una máquina Linux, intente http://www.cygwin.com/

Quizás alguien más pueda sugerir otra alternativa de Windows. Encuentro que la forma de masilla de manejar claves SSH almacenándolas en el registro en un formato no estándar es molesto de extraer.

Caridad Leschinski
fuente
En Windows usando h ssh en cygwin(tienes que descargar el opensslpaquete y las dependencias) que he podido descargar ~/.ssh/known_hosts. Gracias a @CharityAbbott.
taringamberini
10

Proporcione la clave rsa pública del host: -

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

session.setKnownHosts(new ByteArrayInputStream(knownHostPublicKey.getBytes()));
Mark Beer
fuente
1
No funcionó para mí con jsch versión 0.1.50 (siempre tenía un NPE en jsch) pero con la versión más reciente 0.1.53 está funcionando.
Udo
¿Esto (String.getBytes ()) proporcionará una matriz de bytes de caracteres codificados en Unicode, cuando el código Jsch (Util.byte2str ()) espera la codificación UTF-8?
rico p
7

También puedes simplemente hacer

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

No es seguro y es una solución alternativa que no es adecuada para entornos en vivo, ya que deshabilitará la comprobación de claves de host mundialmente conocidas.

Amaury D
fuente
2
Si bien este código puede ayudar a responder la pregunta, las respuestas de solo código no son de alta calidad. Una mejor respuesta explicaría lo que hace el código, le indicará dónde insertarlo, explicará por qué se adoptó este enfoque y vincularía a la documentación relevante.
Stephen Ostermiller
6

También puede ejecutar el siguiente código. Está probado y funcionando.

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

Por favor sustituya los valores apropiados.

Vishnu Prasad Kallummel
fuente
Sí, lo había agregado para mi referencia. Quitaré eso. Gracias.
Vishnu Prasad Kallummel
1
esto creó algún tipo de problemas de autenticación extraños al conectarse a ciertos servidores SSH que ofrecen un método de autenticación interactivo con el teclado. Lo usé durante años para deshacerme de Key y luego me quemé hoy con un servidor determinado. Porque no proporcioné el PW a través de getPassword () sino directamente al objeto Session. Ten eso en mente. No lo usaría más.
Marc
1

Simplemente sustituya "usuario", "pase", "SSHD_IP". Y cree un archivo llamado known_hosts.txt con el contenido del servidor ~ / .ssh / known_hosts. Obtendrás una concha.

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
fuente
No, no me funciona. Del mismo modo, la respuesta de Eric Leschinski / Rakesh Acharya falla si comento. config.put("StrictHostKeyChecking", "no"); Una ssh -vconexión manual revela que el .ssh/known_hostsarchivo contiene la clave ( ecdsa-sha2-nistp256) pero el código hace esto: 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
Ha pasado algún tiempo, lo que trataría de hacer es usar la versión de la biblioteca JSCH disponible el 13 de junio de 2013, porque las cosas probablemente han cambiado en la biblioteca desde entonces
dalvarezmartinez1
1

configurar el host conocido es mejor que configurar el valor de impresión de fingura.

Cuando configure el host conocido, intente ssh manualmente (por primera vez, antes de que se ejecute la aplicación) desde el cuadro en que se ejecuta la aplicación.

sreenath V
fuente
1

Perdí mucho tiempo en este estúpido problema, y ​​creo que el mensaje es bastante correcto "no hay un host en el archivo al que estoy accediendo", pero puede tener más de un archivo know_host en su sistema (como ejemplo i Estoy usando mobaXterm y se mantiene dentro del directorio de instalación que monta el hogar desde esa raíz).

Si está experimentando: está funcionando desde la línea de comandos pero no desde la aplicación, intente acceder a su servidor remoto con ssh y verifique con la opción detallada -v qué archivo se usa actualmente, un ejemplo a continuación:

 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

como puede ver, la clave se encontró en:

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

y no en mi casa de Windows en C: \ Users \ my_local_user \ .ssh, simplemente los fusioné y alineé para resolver el problema.

Espero que esto ayude a alguien en el futuro

loreii
fuente
0

¿Alguien ha podido resolver este problema? Estoy usando Jscp para scp archivos usando autenticación de clave pública (no quiero usar autenticación de contraseña). ¡La ayuda será apreciada!

Esta entrada de stackoverflow trata sobre la comprobación de la clave del host, y no hay relación con la autenticación de clave pública.

En cuanto a la autenticación de clave pública, pruebe el siguiente ejemplo con su clave privada simple (no cifrada),

ymnk
fuente
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
fuente