Использовать подпроцесс для отправки пароля

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

from subprocess import Popen, PIPE

proc = Popen(['sftp','[email protected]', 'stop'], stdin=PIPE)
proc.communicate('password')

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

Ответы

Ответ 1

Возможно, вместо этого вы должны использовать expect -like?

Например Pexpect (пример). Существуют и другие аналогичные библиотеки python.

Ответ 2

Try

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

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

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

Ответ 3

from subprocess import Popen, PIPE

proc = Popen(['sftp','[email protected]', 'stop'], stdin=PIPE)
proc.communicate(input='password')

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

Ответ 4

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

Ответ 5

Используйте 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

Ответ 6

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

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 будет интерпретироваться интерпретатором как "ложный".

Ответ 7

Это чистое решение 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)

Ответ 8

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

from getpass import getpass
from subprocess import Popen, PIPE

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

Ответ 9

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)