Как подключиться по SSH к серверу за другим сервером SSH с помощью JSch?

Мне нужно иметь возможность подключиться по ssh из программы Java к удаленному серверу, а оттуда по SSH на другой сервер. У меня есть учетные данные для обоих серверов на моем клиенте.

Команды будут передаваться автоматически из приложения в виде обычных строк (без ввода пользователем). Мне нужно иметь возможность запускать эти пользовательские команды на втором сервере и решать, какие команды выполнять во время выполнения, на основе вывода и некоторой простой логики.

Могу ли я использовать JSch для этого, и если да, то с чего начать? (Примеры, информация)

=============================================================

ДОБАВЛЕН:

Исключение в потоке «основной» com.jcraft.jsch.JSchException: UnknownHostKey: host.net. Отпечаток ключа RSA — «бла-бла-бла»

как и до сих пор, я решаю эту проблему, изменяя файл known_hosts и добавляя туда хост вручную. Могу ли я обойти эту небольшую проблему, настроив где-нибудь параметр, сообщающий JSch, чтобы он автоматически нажимал YES, когда задается этот вопрос YES-NO?


person Martin Klosi    schedule 21.07.2011    source источник


Ответы (3)


Чтобы подключиться ко второму серверу за брандмауэром, в принципе есть два варианта.

Наивным было бы вызвать ssh на первом сервере (из exec-канала), указав правильный сервер. Для этого потребуется переадресация агента с помощью JSch, а также не предоставляется API JSch для доступа ко второму серверу, только командная строка ssh.

Лучше было бы использовать подключение к первому серверу для создания туннеля TCP и использовать этот туннель для подключения ко второму серверу. JSch Wiki содержит класс ProxySSH (вместе с некоторым примером кода ), что позволяет использовать сеанс JSch в качестве туннеля для второго сеанса JSch. (Отказ от ответственности: этот класс был написан в основном мной при некоторой поддержке автора JSch.)

Когда у вас есть подключение ко второму серверу, используйте либо канал shell, либо серию каналов exec для выполнения ваших команд. (См. Канал Shell, Exec или Subsystem в JSch Wiki для обзора и Javadocs для подробностей.)


Для вашей проблемы с неизвестным ключом хоста:

В безопасной версии все ключи хоста собираются (безопасным способом) и помещаются в файл known_hosts. (Если вы просто доверяете представленному вам ключу, вы уязвимы для атаки «человек посередине». Если это не представляет опасности для вашей сети, поскольку она физически защищена, это хорошо для вас.)

удобная версия устанавливает параметр конфигурации StrictHostKeyChecking to no — это добавит неизвестные ключи хоста в файл ключей хоста:

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

(Вы также можете установить его индивидуально для сеансов, если вы хотите установить его только для проксируемых сеансов, а не для сеанса туннеля. Или переопределить его для сеанса туннеля с помощью yesили ask — там опасность MITM может быть больше.)

срединным способом было бы включить фактический запрос пользователя (который затем должен сравнить отпечатки пальцев с некоторым списком) - для этого реализуйте UserInfo и предоставить объект сеансу. (Вики JSch содержит пример реализации с использованием Swing JOptionPanes, который вы можете просто использовать, если ваша клиентская программа работает в системе с графическим интерфейсом.)

Чтобы сохранение принятых ключей хоста работало, необходимо использовать ссылку JSch.setKnownHosts с аргументом имени файла, а не с аргументом InputStream, иначе вам придется повторять принятие для каждого перезапуска вашего клиента.

person Paŭlo Ebermann    schedule 21.07.2011
comment
работает отлично!. могу ли я использовать один и тот же шлюз для доступа к двум или более разным серверам SSH за этим шлюзом? - person Martin Klosi; 21.07.2011
comment
@Martin: Да, я использовал его таким образом (для доступа к примерно 23 серверам, скрытым за одним шлюзом). - person Paŭlo Ebermann; 22.07.2011
comment
Собственно, это и было причиной создания класса ProxySSH :-) - person Paŭlo Ebermann; 22.07.2011
comment
@Martin: добавлено к ответу. - person Paŭlo Ebermann; 22.07.2011
comment
ДОБАВЛЕНО: я видел, что вы упомянули агента пересылки JSch ssh. как я могу это использовать? Я не видел примеров по этому поводу. Хотя ProxySSH отлично работает, на самом деле он мне не нужен для моей цели, поскольку пользовательскую команду, которую мне нужно запустить на втором хосте, я могу запустить с прокси-хоста, но мне нужно иметь возможность пересылать учетные данные ssh на Это. - person Martin Klosi; 23.07.2011
comment
Никогда не пробовал, но есть метод setAgentForwarding на ChannelShellChannelExec/ChannelSubsystem). - person Paŭlo Ebermann; 23.07.2011
comment
Когда я пытаюсь это сделать, он просто зависает на неопределенный срок без всякой причины. - person Magic Octopus Urn; 11.04.2018
comment
Кроме того, ваши ссылки мертвы. - person Magic Octopus Urn; 11.04.2018
comment
@MagicOctopusUrn, к сожалению, вики JSch исчезла, я ничего не могу с этим поделать. Ссылки на Javadoc должны быть все еще там, хотя они относятся к версии JSch 7,5-летней давности. Я не знаю, что именно вы пробовали, поэтому я не могу бесконечно комментировать ваши зависания без причины (кроме того, что, вероятно, это не так). - person Paŭlo Ebermann; 11.04.2018
comment
Обратите внимание, что StrictHostKeyChecking=no не добавит неизвестные ключи хоста в файл ключей хоста самостоятельно. Вам также необходимо указать путь к файлу ключей хоста, используя setKnownHosts. - person Martin Prikryl; 29.03.2019

Используйте SSH-туннель, также известный как переадресация локального порта, чтобы открыть соединение SSH/SFTP с B через A.

Session sessionA = jsch.getSession("usernameA", "hostA");
// ...
sessionA.connect();

int forwardedPort = 2222; // any port number which is not in use on the local machine
sessionA.setPortForwardingL(forwardedPort, "hostB", 22);

Session sessionB = jsch.getSession("usernameB", "localhost", forwardedPort);
// ...
sessionB.connect();

// Use sessionB here for shell/exec/sftp

Возможно, вам придется обработать UnknownHostKey исключение.

person Martin Prikryl    schedule 02.05.2018

Это может помочь любому. Работает отлично:

 public static void sesionA(){
     try {
        Session sessionA = jSch.getSession(username, hostA);  
        Properties config = new Properties(); 
        config.put("StrictHostKeyChecking", "no");
        sessionA.setConfig(config);
        sessionA.setPassword(passwordA);
        sessionA.connect();


        if(sessionA.isConnected()) {
            System.out.println("Connected host A!");
            forwardedPort = 2222;
            sessionA.setPortForwardingL(forwardedPort, hostB, 22);      
        }

    } catch (JSchException e) {
        e.printStackTrace();
    }
 }

 public static void sesionB(){


        try {
            Session sessionB = jSch.getSession(username, "localhost", forwardedPort);

            Properties config = new Properties(); 
            config.put("StrictHostKeyChecking", "no");
            sessionB.setConfig(config);
            sessionB.setPassword(passwordB);
            sessionB.connect();

          if(sessionB.isConnected()) {
             System.out.println("Connected host B!");
          }
     }
 }
person MocaccinoFan    schedule 26.07.2018
comment
Это просто раздутый код мой ответ. + Никогда и никому не предлагайте использовать StrictHostKeyChecking без объяснения последствий для безопасности. – Вы теряете защиту от MITM-атак, выполняя do. - person Martin Prikryl; 26.07.2018