【问题标题】:SSH Password through Python Subprocess通过 Python 子进程的 SSH 密码
【发布时间】:2012-10-14 01:14:01
【问题描述】:

我正在编写一个 GUI 程序来为一群害怕使用命令行的用户生成和监控 SSH 隧道。

不幸的是,有问题的服务器非常严格。通过 RSA SecurID 令牌进行的双重身份验证是唯一官方认可的打开 SSH 连接的方式。不允许无密码的 RSA 公钥/私钥身份验证。

因此,我的程序有必要从文本输入框中读取密码并将其发送给子 SSH 进程。不幸的是,ssh 竭尽全力确保密码仅来自真正的键盘。

我强烈不喜欢使用第三方模块。我知道 paramiko 和 pexpect(它们都被提出来作为类似问题的可能解决方案),但是试图向我的用户解释如何从源代码安装 Python 模块太让人头疼了。

那么:如何使用标准 python subprocess 模块向 ssh 子进程发送密码?有什么办法可以让子进程误以为我在使用 TTY?是否可以使用 SSH_ASKPASS 读取我的程序?

也允许使用其他标准库模块(例如,带有 os 模块的低级命令)。

【问题讨论】:

  • 大多数情况下,您只需将模块的源目录从 tarball 中拉出并与您自己的脚本一起打包,这样就无需安装它。
  • 我同意 pexpect 是完成这项工作的工具。您还可以考虑使用 PyInstaller,它将依赖项(和解释器)捆绑成可执行形式。
  • 我认为你可以通过ssh -TSSH_ASKPASS 获得成功,这似乎正是为此目的而发明的。
  • 您需要使用 pty 将其作为子进程运行。您可以使用 os.openpty() 和那里的其他功能“自己动手”。
  • @mlefavor:不,但您可以提供与父进程通信的外部二进制文件。不好的是,无论我怎么尝试,到目前为止我都没有让 SSH 使用 SSH_ASKPASS。

标签: python ssh


【解决方案1】:

最后,我能够使用 pty 模块通过伪终端控制 ssh。我在pexpect 中编写了一个解决方案,然后通过查看 pexpect 源代码并从this StackOverflow answer 获得一些帮助,我能够弄清楚该怎么做。这是相关代码的摘录(作为对象方法的一部分执行;因此引用了self)。

command = [
        '/usr/bin/ssh',
        '{0}@{1}'.format(username, hostname),
        '-L', '{0}:localhost:{1}'.format(local_port, foreign_port),
        '-o', 'NumberOfPasswordPrompts=1',
        'sleep {0}'.format(SLEEP_TIME),
]

# PID = 0 for child, and the PID of the child for the parent    
self.pid, child_fd = pty.fork()

if not self.pid: # Child process
    # Replace child process with our SSH process
    os.execv(command[0], command)

while True:
    output = os.read(child_fd, 1024).strip()
    lower = output.lower()
    # Write the password
    if lower.endswith('password:'):
        os.write(child_fd, self.password_var.get() + '\n')
        break
    elif 'are you sure you want to continue connecting' in lower:
        # Adding key to known_hosts
        os.write(child_fd, 'yes\n')
    elif 'company privacy warning' in lower:
        pass # This is an understood message
    else:
        tkMessageBox.showerror("SSH Connection Failed",
            "Encountered unrecognized message when spawning "
            "the SSH tunnel: '{0}'".format(output))
        self.disconnect()

【讨论】:

    猜你喜欢
    • 2020-05-16
    • 2013-01-19
    • 1970-01-01
    • 2016-12-02
    • 2018-03-16
    • 1970-01-01
    • 2016-06-30
    • 2013-11-22
    • 2012-02-23
    相关资源
    最近更新 更多