Используйте подпроцесс для отправки пароля - PullRequest
16 голосов
/ 05 марта 2010

Я пытаюсь использовать модуль подпроцесса python для входа на защищенный FTP-сайт, а затем получить файл. Однако я продолжаю зацикливаться на том, что просто пытаюсь отправить пароль при запросе. У меня пока есть следующий код:

from subprocess import Popen, PIPE

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

Это все еще останавливается при запросе пароля. Если я ввожу пароль вручную, он переходит на FTP-сайт, а затем вводит пароль в командной строке. Я видел, как люди предлагают использовать pexpect, но вкратце мне нужно стандартное библиотечное решение. Есть ли в любом случае с подпроцессом и / или любой другой stdlib? Что я забыл выше?

Ответы [ 8 ]

8 голосов
/ 05 марта 2010

Возможно, вам следует вместо этого использовать ожидаемую -подобную библиотеку?

Например Pexpect ( пример ).Существуют и другие похожие библиотеки Python.

6 голосов
/ 05 марта 2010

Попробуйте

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

Это должно сработать.

То, что вы описываете, звучит как stdin=None, где дочерний процесс наследует stdin родителя (ваша программа Python).

2 голосов
/ 19 января 2018
from subprocess import Popen, PIPE

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

Попробуйте ввести = пароль в сообщении, который мне помог.

1 голос
/ 12 декабря 2016

Используйте 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
1 голос
/ 05 марта 2010

Я бы порекомендовал отказаться от подхода с использованием подпроцесса и использовать пакет paramiko для доступа по sftp.

0 голосов
/ 21 мая 2019

Самый безопасный способ сделать это - запросить пароль заранее и затем передать его в команду. Запрос пароля не позволит сохранить пароль где-либо в вашем коде. Вот пример:

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())
0 голосов
/ 10 августа 2018

Это чистое решение Python, использующее ожидаемый, а не pexpect.

Если в Ubuntu вам сначала нужно установить ожидайте с:

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)
0 голосов
/ 26 марта 2018

Эта та же самая проблема мучила меня в течение недели. Мне пришлось безопасно вводить пароль из пользовательского ввода через подпроцесс, потому что я пытался избежать введения уязвимости внедрения команд. Вот как я решил проблему с небольшой помощью коллеги.

import subprocess

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

.wait (timeout = int) был самым важным компонентом, поскольку он позволяет пользователю передавать ввод в stdin. В противном случае тайм-аут по умолчанию равен 0 и не оставляет пользователю времени для ввода данных, что приводит к появлению строки None или null. Взял меня навсегда, чтобы понять это.

Для повторных случаев использования, когда вы знаете, что вам придется делать это несколько раз, вы можете переопределить функцию 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 естественным образом перейдет в окно оболочки и позволит пользователю передать ввод в popen ().

Кроме того, просто чтобы объяснить, почему вы возвращаете proc_h.poll () == os.EX_OK, он возвращает 0, если команда выполнена успешно. Это просто рекомендация в стиле c, когда вы хотите возвращать системные коды ошибок в случае сбоя функции, в то время как учёт того факта, что возвращаемый 0 будет интерпретироваться интерпретатором как «false».

...