使用subprocess.Popen通过SSH或SCP发送密码

Cha*_*l72 10 python linux ssh subprocess python-3.x

我正在尝试使用scp(安全复制)命令subprocess.Popen.登录要求我发送密码:

from subprocess import Popen, PIPE

proc = Popen(['scp', "user@10.0.1.12:/foo/bar/somefile.txt", "."], stdin = PIPE)
proc.stdin.write(b'mypassword')
proc.stdin.flush()
Run Code Online (Sandbox Code Playgroud)

这会立即返回错误:

user@10.0.1.12's password:
Permission denied, please try again.
Run Code Online (Sandbox Code Playgroud)

确定密码是正确的.我通过手动调用scpshell 轻松验证它.那么为什么这不起作用呢?

请注意,有许多类似的问题,询问subprocess.Popen并发送自动SSH或FTP登录的密码:

如何从python脚本在linux中设置用户密码?
使用子进程发送密码

这些问题的答案不起作用和/或不适用,因为我使用的是Python 3.

sjb*_*jbx 10

这是ssh使用密码的函数pexpect:

def ssh(host, cmd, user, password, timeout=30, bg_run=False):                                                                                                 
    """SSH'es to a host using the supplied credentials and executes a command.                                                                                                 
    Throws an exception if the command doesn't return 0.                                                                                                                       
    bgrun: run command in the background"""                                                                                                                                    

    fname = tempfile.mktemp()                                                                                                                                                  
    fout = open(fname, 'w')                                                                                                                                                    

    options = '-q -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -oPubkeyAuthentication=no'                                                                         
    if bg_run:                                                                                                                                                         
        options += ' -f'                                                                                                                                                       
    ssh_cmd = 'ssh %s@%s %s "%s"' % (user, host, options, cmd)                                                                                                                 
    child = pexpect.spawn(ssh_cmd, timeout=timeout)                                                                                                                            
    child.expect(['password: '])                                                                                                                                                                                                                                                                                               
    child.sendline(password)                                                                                                                                                   
    child.logfile = fout                                                                                                                                                       
    child.expect(pexpect.EOF)                                                                                                                                                  
    child.close()                                                                                                                                                              
    fout.close()                                                                                                                                                               

    fin = open(fname, 'r')                                                                                                                                                     
    stdout = fin.read()                                                                                                                                                        
    fin.close()                                                                                                                                                                

    if 0 != child.exitstatus:                                                                                                                                                  
        raise Exception(stdout)                                                                                                                                                

    return stdout
Run Code Online (Sandbox Code Playgroud)

应该可以使用类似的东西scp.


Ken*_*ter 7

OpenSSH scp实用程序调用ssh程序以建立与远程主机的SSH连接,并且ssh进程处理身份验证.该ssh实用程序不接受命令行或其标准输入上的密码.我相信这是OpenSSH开发人员的一个深思熟虑的决定,因为他们认为人们应该使用更安全的机制,如基于密钥的身份验证.任何调用ssh的解决方案都将遵循以下方法之一:

  1. 使用SSH密钥进行身份验证,而不是密码.
  2. 使用sshpass,expect或类似工具自动响应密码提示.
  3. 使用(滥用)的SSH_ASKPASS功能来获取ssh通过调用另一个命令,描述以获取密码这里这里,或在一些问题的答案在这里.
  4. 让SSH服务器管理员启用基于主机的身份验证并使用它.请注意,基于主机的身份验证仅适用于某些网络环境.请在此处此处查看其他说明.
  5. 使用perl,python,java或您喜欢的语言编写自己的ssh客户端.大多数现代编程语言都有ssh客户端库,您可以完全控制客户端获取密码的方式.
  6. 下载ssh源代码并构建一个ssh可以按您希望的方式工作的修改版本.
  7. 使用不同的ssh客户端.还有其他ssh客户端,包括免费和商业.其中一个可能比OpenSSH客户端更适合您的需求.

在这种特殊情况下,鉴于您已经scp从python脚本调用,似乎其中一个是最合理的方法:

  1. 使用pexpect(python expect模块)来调用scp并提供密码.
  2. 使用python ssh实现的paramiko来执行此ssh任务,而不是调用外部程序.


ent*_*opy 6

您链接的第二个答案表明您使用Pexpect(这通常是与期望输入的命令行程序交互的正确方法).它有一个分叉,适用于你可以使用的python3.


Tom*_*mmy 5

Pexpect 有一个专门用于此的库:pxssh

http://pexpect.readthedocs.org/en/stable/api/pxssh.html

import pxssh
import getpass
try:
    s = pxssh.pxssh()
    hostname = raw_input('hostname: ')
    username = raw_input('username: ')
    password = getpass.getpass('password: ')
    s.login(hostname, username, password)
    s.sendline('uptime')   # run a command
    s.prompt()             # match the prompt
    print(s.before)        # print everything before the prompt. 
    s.logout()
except pxssh.ExceptionPxssh as e:
    print("pxssh failed on login.")
    print(e)
Run Code Online (Sandbox Code Playgroud)