web-dev-qa-db-ja.com

サブプロセスを使用してパスワードを送信する

pythonサブプロセスモジュールを使用して安全なFTPサイトにログインし、ファイルを取得しようとしています。しかし、要求されたときにパスワードを送信しようとするだけでハングアップし続けます。私は今のところ次のコードを持っています:

from subprocess import Popen, PIPE

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

これはまだパスワードプロンプトで停止します。パスワードを手動で入力すると、ftpサイトに移動し、コマンドラインにパスワードを入力します。私は人々がpexpectの使用を提案するのを見てきましたが、長い話をすれば、標準ライブラリソリューションが必要です。とにかくサブプロセスや他のstdlibを使用していますか?上記の何を忘れていますか?

20
The Jug

おそらく、代わりに expect -likeライブラリを使用する必要がありますか?

たとえば Pexpectexample )。他にも、同様のpythonライブラリがあります。

8
codeape

試す

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

うまくいくはずです。

stdin=None子プロセスは親のstdinを継承します(your Python program))。

7
Aaron Digulla
from subprocess import Popen, PIPE

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

通信でinput = ‘password’を使用してみてください。これでうまくいきました。

3
0038lana

サブプロセスアプローチを廃止し、sftpアクセスにparamikoパッケージを使用することをお勧めします。

1
mikerobi

SFTPにはParamikoを使用します。それ以外の場合、これは機能します:

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
Matthew Moisen

これを行う最も安全な方法は、事前にパスワードを要求してから、それをコマンドにパイプすることです。パスワードを要求することで、コードのどこかにパスワードを保存する必要がなくなります。次に例を示します。

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
Josh Correia

これは、pexpectではなく、expectを使用した純粋なPythonソリューションです。

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
Duke Dougal

パスワードの改行(ユーザーがEnterキーを押す)を忘れただけです。

_from subprocess import Popen, PIPE

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

また、.encode()はデフォルトでproc.communicate()がバイトのようなオブジェクトを受け入れるためです。

0
Nicolas Karolak

これと同じ問題が1週間悩みました。コマンドインジェクションの脆弱性の導入を回避しようとしたため、サブプロセスを通じてユーザー入力からパスワードを安全に送信する必要がありました。これが、同僚の助けを借りて問題を解決した方法です。

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"として扱われることを考慮に入れています。

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)