使用子进程发送密码

时间:2010-03-05 15:16:28

标签: python subprocess sftp

我正在尝试使用python子进程模块登录到安全的ftp站点然后获取文件。但是,我一直在试图在请求密码时发送密码。到目前为止,我有以下代码:

from subprocess import Popen, PIPE

proc = Popen(['sftp','user@server', 'stop'], stdin=PIPE)
proc.communicate('password')

这仍然在密码提示下停止。如果我手动输入密码,则转到ftp站点,然后在命令行输入密码。我见过人们建议使用pexpect,但长话短说我需要一个标准的库解决方案。无论如何还有子进程和/或任何其他stdlib?我上面忘记了什么?

12 个答案:

答案 0 :(得分:8)

也许您应该使用类似expect的库?

例如Pexpectexample)。还有其他类似的python库。

答案 1 :(得分:6)

尝试

proc.stdin.write('yourPassword\n')
proc.stdin.flush()

这应该有效。

您所描述的内容听起来像stdin=None,其中子进程继承父进程的stdin(您的Python程序)。

答案 2 :(得分:2)

from subprocess import Popen, PIPE

proc = Popen(['sftp','user@server', 'stop'], stdin=PIPE)
proc.communicate(input='password')

尝试使用input ='password'进行沟通,这对我有用。

答案 3 :(得分:1)

我建议废弃子流程方法并使用paramiko包进行sftp访问。

答案 4 :(得分:1)

使用Paramiko进行SFTP。对于其他任何事情,这都有效:

import subprocess

args = ['command-that-requires-password', '-user', 'me']

proc = subprocess.Popen(args, 
                        stdin=subprocess.PIPE, 
                        stdout=subprocess.PIPE, 
                        stderr=subprocess.PIPE)

proc.stdin.write('mypassword\n')
proc.stdin.flush()

stdout, stderr = proc.communicate()
print stdout
print stderr

答案 5 :(得分:0)

同样的问题困扰了我一个星期。我必须通过子进程安全地从用户输入提交密码,因为我试图避免引入命令注入漏洞。以下是我在同事的帮助下解决问题的方法。

import subprocess

command = ['command', 'option1', '--password']
subprocess.Popen(command, stdin=subprocess.PIPE).wait(timeout=60)

.wait(timeout = int)是最重要的组件,因为它允许用户将输入提供给stdin。否则,超时默认为0并使用户没有时间输入输入,从而导致无字符串或空字符串。让我永远想清楚这一点。

对于你知道你必须多次执行此操作的重复用例,你可以覆盖popen函数并将其用作私有方法,如果你预期,同一个程序员告诉我这是最好的做法其他人有兴趣稍后维护代码,你不希望他们搞砸它。

def _popen(cmd):
   proc_h = subprocess.Popen(cmd, stdin=subprocess.PIPE)
   proc_h.wait(timeout=60)
   return proc_h.poll() == os.EX_OK

如果要提示用户输入,则删除stdout = subprocess.PIPE非常重要。否则,该过程似乎挂起60秒,并且用户没有得到提示,也没有意识到他们应该提供密码。 stdout将自然地转到shell窗口并允许用户将输入传递给popen()。

另外,只是为了解释为什么返回proc_h.poll()== os.EX_OK,如果命令成功则返回0。当你想要在函数失败的情况下返回系统错误代码时,这只是c风格的最佳实践,同时考虑到返回0将被视为" false"由翻译。

答案 6 :(得分:0)

这是使用Expect的纯Python解决方案,而不是pexpect。

如果在Ubuntu上,您首先需要使用以下命令安装Expect:

sudo apt install expect

Python 3.6或更高版本:

def sftp_rename(from_name, to_name):
    sftp_password = 'abigsecret'
    sftp_username = 'foo'
    destination_hostname = 'some_hostname'
    from_name = 'oldfilename.txt'
    to_name = 'newfilename.txt'
    commands = f"""
spawn sftp -o "StrictHostKeyChecking no" 
{sftp_username}@{destination_hostname}
expect "password:"
send "{sftp_password}\r"
expect "sftp>"
send "rename {from_name} {to_name}\r"
expect "sftp>"
send "bye\r"
expect "#"
"""
    sp = subprocess.Popen(['expect', '-c', commands], stdin=subprocess.PIPE, stdout=subprocess.PIPE)

答案 7 :(得分:0)

最安全的方法是事先提示输入密码,然后将其输入命令。提示输入密码将避免将密码保存在代码中的任何位置。这是一个示例:

from getpass import getpass
from subprocess import Popen, PIPE

password = getpass("Please enter your password: ")
proc = Popen("sftp user@server stop".split(), stdin=PIPE)
# Popen only accepts byte-arrays so you must encode the string
proc.communicate(password.encode())

答案 8 :(得分:0)

import subprocess

args = ['command', 'arg1', 'arg2']

proc = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, 
    stderr=subprocess.PIPE)

proc.stdin.write(b'password') ##The b prefix is necessary because it needs a byte type

proc.stdin.flush()

stdout, stderr = proc.communicate()

print(stdout)

print(stderr)

答案 9 :(得分:0)

您只是忘记了密码中的换行符(又名用户按下Enter键)。

from subprocess import Popen, PIPE

proc = Popen(['sftp','user@server', 'stop'], stdin=PIPE)
proc.communicate('password\n'.encode())

.encode(),因为默认情况下proc.communicate()接受类似字节的对象。

答案 10 :(得分:0)

由于某种原因,我在这里无法获得任何标准库答案来为我工作-所有这些都遇到了非常奇怪的问题。这里的其他人:unable to provide password to a process with subprocess [python]遇到了同样的问题,并得出结论,最终,您只需要使用pexpect就能发送密码。

我想在这里添加我的最终代码,以节省任何有类似问题的人的时间,因为我在此上浪费了很多时间(Python 3,2020):

ssh_password = getpass("user's password: ")
ssh_password = (ssh_password + "\n").encode()

scp_command = 'scp xx.xx.xx.xx:/path/to/file.log /local/save/path/'

child = pexpect.spawn(scp_command)
# make output visible for debugging / progress watching
child.logfile = sys.stdout.buffer

i = child.expect([pexpect.TIMEOUT, "password:"])
if i == 0:
    print("Got unexpected output: {} {}".format(child.before, child.after))
    return
else:
    child.sendline(ssh_password)
child.read()

上面的代码运行一个SCP命令,将文件从远程服务器拉到本地计算机上-根据需要更改服务器IP和路径。

要记住的关键事项:

  • child.expect通话中必须有一个pexpect.TIMEOUT
  • 无论传入什么字符串,都必须将其编码为字节,并且必须使用默认的编码
  • 将pexpect输出写入sys.stdout.buffer,以便您实际上可以看到发生了什么
  • 最后必须有child.read()

答案 11 :(得分:0)

由于您想要的只是获取文件,因此我尝试使用“子进程”,但它不适用于我。所以现在我正在使用paramiko,这是我的代码: 这是我在网上找到的一个教程 使用python的paramiko将文件从本地服务器传输到远程服务器,反之亦然 “ https://www.youtube.com/watch?v=dtvV2xKaVjw”

下面是我的代码,用于将一个文件夹中的所有文件从Linux传输到Windows

import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='11.11.11.1111', username='root', password='********', port=22)
sftp_client = ssh.open_sftp()
source_folder = '/var/ftp/file_pass'
local_folder = 'C:/temp/file_pass'
inbound_files = sftp_client.listdir(source_folder)
print(inbound_files)

for ele in inbound_files:
    try:
        path_from = source_folder + '/' + ele
        path_to = local_folder + '/'+ ele
        sftp_client.get(path_from, path_to)
    except:
        print(ele)

sftp_client.close()
ssh.close()