Linux 使用 subprocess.Popen 通过 SSH 或 SCP 发送密码
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15166973/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Sending a password over SSH or SCP with subprocess.Popen
提问by Channel72
I'm trying to run an scp
(secure copy) command using subprocess.Popen
. The login requires that I send a password:
我正在尝试scp
使用subprocess.Popen
. 登录要求我发送密码:
from subprocess import Popen, PIPE
proc = Popen(['scp', "[email protected]:/foo/bar/somefile.txt", "."], stdin = PIPE)
proc.stdin.write(b'mypassword')
proc.stdin.flush()
This immediately returns an error:
这立即返回一个错误:
[email protected]'s password:
Permission denied, please try again.
I'm certainthe password is correct. I easily verify it by manually invoking scp
on the shell. So why doesn't this work?
我确定密码是正确的。我通过scp
在 shell 上手动调用来轻松验证它。那么为什么这不起作用呢?
Note, there are many similar questions to this, asking about subprocess.Popen
and sending a password for automated SSH or FTP login:
请注意,有许多与此类似的问题,询问subprocess.Popen
并发送用于自动 SSH 或 FTP 登录的密码:
How can I set a users password in linux from a python script?
Use subprocess to send a password
如何从python脚本在linux中设置用户密码?
使用子进程发送密码
The answer(s) to these questions don't work and/or don't apply because I am using Python 3.
这些问题的答案不起作用和/或不适用,因为我使用的是 Python 3。
采纳答案by entropy
回答by sjbx
Here's a function to ssh
with a password using pexpect
:
这是一个ssh
使用密码的函数pexpect
:
import 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) #spawnu for Python 3
child.expect(['[pP]assword: '])
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
Something similar should be possible using scp
.
使用scp
.
回答by Tommy
Pexpect has a library for exactly this: pxssh
Pexpect 有一个专门用于此的库:pxssh
http://pexpect.readthedocs.org/en/stable/api/pxssh.html
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)
回答by Raju Pitta
I guess some applications interact with the user using stdin and some applications interact using terminal. In this case when we write the password using PIPE we are writing to stdin. But SCP application reads the password from terminal. As subprocess cannot interact with user using terminal but can only interact using stdin we cannot use the subprocess module and we must use pexpect for copying the file using scp.
我猜有些应用程序使用 stdin 与用户交互,有些应用程序使用终端进行交互。在这种情况下,当我们使用 PIPE 写入密码时,我们正在写入标准输入。但是 SCP 应用程序从终端读取密码。由于子进程不能使用终端与用户交互,而只能使用标准输入进行交互,我们不能使用子进程模块,我们必须使用 pexpect 使用 scp 复制文件。
Feel free for corrections.
随意更正。
回答by Kenster
The OpenSSH scp
utility invokes the ssh
program to make the SSH connection to the remote host, and the ssh process handles authentication. The ssh
utility doesn't accept a password on the command line or on its standard input. I believe this is a deliberate decision on the part of the OpenSSH developers, because they feel that people should be using more secure mechanisms like key-based authentication. Any solution for invoking ssh is going to follow one of these approaches:
OpenSSHscp
实用程序调用该ssh
程序以建立到远程主机的 SSH 连接,并且 ssh 进程处理身份验证。该ssh
实用程序不接受命令行或其标准输入上的密码。我相信这是 OpenSSH 开发人员的一个深思熟虑的决定,因为他们认为人们应该使用更安全的机制,比如基于密钥的身份验证。调用 ssh 的任何解决方案都将遵循以下方法之一:
- Use an SSH keyfor authentication, instead of a password.
- Use sshpass, expect, or a similar tool to automate responding to the password prompt.
- Use (abuse) the SSH_ASKPASS feature to get
ssh
to get the password by invoking another command, described hereor here, or in some of the answers here. - Get the SSH server administrator to enable host-based authenticationand use that. Note that host-based authentication is only suitable for certain network environments. See additional notes hereand here.
- Write your own ssh client using perl, python, java, or your favorite language. There are ssh client libraries available for most modern programming languages, and you'd have full control over how the client gets the password.
- Download the ssh source codeand build a modified version of
ssh
that works the way you want. - Use a different ssh client. There are other ssh clientsavailable, both free and commercial. One of them might suit your needs better than the OpenSSH client.
- 使用SSH 密钥而不是密码进行身份验证。
- 使用sshpass、expect或类似的工具来自动响应密码提示。
- 使用(滥用) SSH_ASKPASS 功能
ssh
通过调用另一个命令来获取密码,在此处或此处或此处的某些答案中进行了描述。 - 让 SSH 服务器管理员启用基于主机的身份验证并使用它。请注意,基于主机的身份验证仅适用于某些网络环境。请参阅此处和此处的附加说明。
- 使用 perl、python、java 或您喜欢的语言编写您自己的 ssh 客户端。有适用于大多数现代编程语言的 ssh 客户端库,您可以完全控制客户端如何获取密码。
- 下载ssh 源代码并构建一个
ssh
按照您想要的方式工作的修改版本。 - 使用不同的 ssh 客户端。还有其他 ssh 客户端可用,包括免费的和商业的。其中之一可能比 OpenSSH 客户端更适合您的需求。
In this particular case, given that you're already invoking scp
from a python script, it seems that one of these would be the most reasonable approach:
在这种特殊情况下,鉴于您已经scp
从 python 脚本调用,似乎其中一种方法是最合理的方法:
回答by Ryan Y
Here is my scp function based on pexpect. It can handle wildcards (i.e. multiple file transfer), in addition to the password. To handle multiple file transfer (i.e. wildcards), we need to issue a command via a shell. Refer to pexpect FAQ.
这是我基于 pexpect 的 scp 函数。除了密码之外,它还可以处理通配符(即多文件传输)。要处理多个文件传输(即通配符),我们需要通过 shell 发出命令。请参阅pexpect 常见问题解答。
import pexpect
def scp(src,user2,host2,tgt,pwd,opts='',timeout=30):
''' Performs the scp command. Transfers file(s) from local host to remote host '''
cmd = f'''/bin/bash -c "scp {opts} {src} {user2}@{host2}:{tgt}"'''
print("Executing the following cmd:",cmd,sep='\n')
tmpFl = '/tmp/scp.log'
fp = open(tmpFl,'wb')
childP = pexpect.spawn(cmd,timeout=timeout)
try:
childP.sendline(cmd)
childP.expect([f"{user2}@{host2}'s password:"])
childP.sendline(pwd)
childP.logfile = fp
childP.expect(pexpect.EOF)
childP.close()
fp.close()
fp = open(tmpFl,'r')
stdout = fp.read()
fp.close()
if childP.exitstatus != 0:
raise Exception(stdout)
except KeyboardInterrupt:
childP.close()
fp.close()
return
print(stdout)
It can be used this way:
它可以这样使用:
params = {
'src': '/home/src/*.txt',
'user2': 'userName',
'host2': '192.168.1.300',
'tgt': '/home/userName/',
'pwd': myPwd(),
'opts': '',
}
scp(**params)