【问题标题】:How to intercept SSH Password request in a Java Program如何在 Java 程序中拦截 SSH 密码请求
【发布时间】:2013-12-22 08:51:43
【问题描述】:

我需要使用 ProcessBuilder 和 USERID/PASSWORD 组合从 JAVA 程序生成 SSH 连接。

我已经使用 Ganymed、JSch、JAVA Processbuilder 和 Expect 脚本(也包括Expect4J)、JAVA ProcessBuilder 和 SSHPASS 脚本以及 SSH 共享密钥的组合成功实现了 SSH 连接。

此时安全性不是问题,我所追求的只是能够以编程方式支持 SSH 连接的各种组合。

我的问题是 SSH 抛出的密码提示不在 STDIN/STDOUT 上(我相信在 tty 上)。这是我要克服的最后一个障碍。

我的问题是有没有办法拦截 SSH 密码请求并从我的 JAVA 代码中提供它?

请注意,这是一个非常狭窄的问题(以上所有信息都是为​​了保证答案不会太宽泛)。

这是我正在尝试的示例代码:

import  java.io.*;
import  java.util.*;

public class ProcessBuilderTest {
    public  static void main(String[] args) throws IOException, Exception {

        ProcessBuilder pb = new ProcessBuilder(
                                "/usr/bin/ssh",
                                "nyuser@myserver.com",
                                "export NOME='Jennifer Lawrence'; echo $NOME"
                                );


        pb.redirectErrorStream(); //redirect stderr to stdout
        Process process = pb.start();
        InputStream inputStream = process.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        String line = null;
        while((line = reader.readLine())!= null) {
            System.out.println(line);
        }
        process.waitFor();
     }
}

但是,当我运行它时,我得到了这个:

[memphis BuilderTest]# java ProcessBuilderTest

myuser@myserver's password: 

在我输入密码后,我得到了剩下的输出:

Jennifer Lawrence

[memphis BuilderTest]# 

再次,具体问题是: 有没有办法使用 PasswordAuthentication 方法(无法使用其他方法)生成外部 ssh 客户端(OpenSSH、Tectia SSH、SecureCRT 等)使用 JAVA ProcessBuilder 接口(无法使用其他语言)的进程,拦截/捕获密码从我的 JAVA 代码中提示并响应/交互提供该密码(因此用户无需键入)?

【问题讨论】:

  • 你为什么要用这么多不同的方式来实现它?!
  • 我的团队正在创建基于 JAVA 的工具供基础架构团队使用,每个团队都有自己的做事方式(它是一家全球性公司),我们不能通过强制标准或模式。
  • 嗯,密码提示以无法被拦截的方式完成是有原因的。原因是程序或脚本中的硬编码密码是不可取的,至少可以这么说。
  • @Ingo,我同意密码不得在任何地方进行硬编码,这不是我们所做的,我可以给你举的一个例子是我们的一些用户(操作员)在一个可能通过许多服务器产生的会话的开始,我们的系统将该信息加密保存在内存中,并在需要时使用它,但是,就像我说的,一些操作将在许多不同国家的服务器中进行/执行,受到许多不同的法规并由许多不同的支持小组维护....因此几乎不可能执行标准。
  • @Ingo 这正是我需要的 :-)

标签: java ssh passwords tty


【解决方案1】:

假设您在 Linux 上操作,您需要了解伪 tty。密码提示在 tty 设备上。您将需要构建一个针对伪 tty 运行的单独进程,而不是仅仅继承您的 tty 设备,然后您可以拦截密码提示。

这是一个中等复杂的过程。

有一个库支持其中的一些:http://www.ganymed.ethz.ch/ssh2/FAQ.html。如果可用,您可能会发现阅读它的源代码会很有启发性。

【讨论】:

  • 我也是这么想的,在这种情况下我的问题是:1.如何在JAVA中分配一个pty(在Linux和Windows上更糟)2.如何触发ssh客户端该 pty 分配。我已经搜索了 iNet l;寻找这个答案(例如一些示例代码),我所看到的只是相当多的人在问同样的问题。 :(
  • Windows 没有相同意义上的 'pty's,我对 Windows 没有任何建议。
  • 首先感谢您的回复。 Ganymed 是我在代码中使用的纯 JAVA SSH 实现之一,因此我将看看它的源代码。
  • 你在这方面有什么收获吗?从 JPty 和其他人的角度来看,以独立于平台的方式或不涉及本机 JNI 调用的方式创建伪 tty 并非易事。我有一个类似的问题,我希望自动登录到 SSH 主机,但我无法捕获密码提示。我的程序提示用户输入他们的密码,因此它没有存储在代码中,而是多次输入。
  • 你知道我多久以前写的。我不再在我做这些事情的地方工作。
【解决方案2】:

虽然有人建议需要伪 tty (pty) 来模拟终端,但接受的答案并不能提供有效的解决方案 - 还有很多类似的问题没有有效的答案。

这里有两种解决方案,可让您在 SSH 中捕获“密码:”提示并以自动方式输入密码,而无需使用 SSH_ASKPASS 或 Expect。

当您可以使用两种编程语言时为什么要使用一种编程语言 - 第一个选项并不理想,但它演示了解决方案:

ProcessBuilder pb = new ProcessBuilder("/usr/bin/python", "-c", "import pty; pty.spawn(['/usr/bin/ssh', '<hostname>'])");

上面的示例使用 Python pty 模块将 SSH 包装到 PTY 中。尽管它很简单,但它并没有提供任何灵活性来允许您修改任何终端属性,例如传递的窗口大小。

另一个更轻量级的选择是在 C 中使用 PTY 包装器 - “UNIX® 环境中的高级编程”一书中的 pty 工具就是这样 - 可以在 https://github.com/abligh/pty 找到源代码。

然后您将以类似的方式使用它,但引用 pty 工具而不是 Python:

ProcessBuilder pb = new ProcessBuilder("/usr/local/bin/pty", "/usr/bin/ssh", "<hostname>");

这与 Expect 用来模拟 PTY 的方法相同,这就是您能够使用 Expect 拦截它的原因。不言而喻,隧道明文密码是不安全的,公钥身份验证应该始终是这样做的首选方式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-16
    • 2019-03-03
    • 2015-06-25
    • 1970-01-01
    • 2014-03-25
    • 2023-04-05
    • 2017-07-13
    • 1970-01-01
    相关资源
    最近更新 更多