使用 subprocess.Popen 通过 SSH 或 SCP 发送密码
- 2024-11-04 08:43:00
- admin 原创
- 37
问题描述:
我正在尝试scp
使用 运行 (安全复制) 命令subprocess.Popen
。登录需要我发送密码:
from subprocess import Popen, PIPE
proc = Popen(['scp', "user@10.0.1.12:/foo/bar/somefile.txt", "."], stdin = PIPE)
proc.stdin.write(b'mypassword')
proc.stdin.flush()
这将立即返回一个错误:
user@10.0.1.12's password:
Permission denied, please try again.
我确信密码是正确的。我可以通过手动调用scp
shell 轻松验证密码。那么为什么这不管用呢?
请注意,有许多类似的问题,询问subprocess.Popen
并发送自动 SSH 或 FTP 登录的密码:
如何使用 Python 脚本在 Linux 中设置用户密码?
使用子进程发送密码
由于我使用的是 Python 3,所以这些问题的答案不起作用或不适用。
解决方案 1:
ssh
这是一个使用密码的函数pexpect
:
import pexpect
import tempfile
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
使用 应该可以实现类似的事情scp
。
解决方案 2:
OpenSSHscp
实用程序调用该ssh
程序与远程主机建立 SSH 连接,而 ssh 进程负责处理身份验证。该ssh
实用程序不接受命令行或标准输入中的密码。我相信这是 OpenSSH 开发人员的故意决定,因为他们认为人们应该使用更安全的机制,如基于密钥的身份验证。任何调用 ssh 的解决方案都将遵循以下方法之一:
使用SSH 密钥进行身份验证,而不是密码。
使用sshpass、expect或类似工具自动响应密码提示。
使用(滥用)SSH_ASKPASS 功能
ssh
通过调用另一个命令来获取密码,如此处或此处所述,或在此处的一些答案中所述。让 SSH 服务器管理员启用基于主机的身份验证并使用它。请注意,基于主机的身份验证仅适用于某些网络环境。请参阅此处和此处的其他说明。
使用 perl、python、java 或您喜欢的语言编写您自己的 ssh 客户端。大多数现代编程语言都有可用的 ssh 客户端库,您可以完全控制客户端如何获取密码。
下载ssh 源代码并构建一个
ssh
按您想要的方式工作的修改版本。使用不同的 ssh 客户端。还有其他可用的 ssh 客户端,既有免费的也有商业的。其中一个可能比 OpenSSH 客户端更适合您的需求。
在这种特殊情况下,鉴于您已经scp
从 python 脚本调用,似乎其中一种方法是最合理的:
使用pexpect(python expect 模块)来调用
scp
它并输入密码。使用paramiko(python ssh 实现)来执行此 ssh 任务,而不是调用外部程序。
解决方案 3:
您链接的第二个答案建议您使用Pexpect(这通常是与需要输入的命令行程序交互的正确方法)。
解决方案 4:
Pexpect 有一个专门用于此的库:pxssh
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)
解决方案 5:
我猜有些应用程序使用 stdin 与用户交互,有些应用程序使用终端交互。在这种情况下,当我们使用 PIPE 写入密码时,我们正在写入 stdin。但 SCP 应用程序从终端读取密码。由于子进程无法使用终端与用户交互,而只能使用 stdin 交互,因此我们不能使用子进程模块,我们必须使用 pexpect 来使用 scp 复制文件。
请随意纠正。
解决方案 6:
这是我基于 pexpect 的 scp 函数。除了密码之外,它还可以处理通配符(即多个文件传输)。要处理多个文件传输(即通配符),我们需要通过 shell 发出命令。请参阅pexpect FAQ。
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='
')
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)
可以这样使用:
params = {
'src': '/home/src/*.txt',
'user2': 'userName',
'host2': '192.168.1.300',
'tgt': '/home/userName/',
'pwd': myPwd(),
'opts': '',
}
scp(**params)
解决方案 7:
这是我根据@Kobayashi 和@sjbx 发布的代码进行重写的,但目的是执行 scp 请求,因此感谢他们两位。
def scp(host, user, password, from_dir, to_dir, timeout=300, recursive=False):
fname = tempfile.mktemp()
fout = open(fname, 'w')
scp_cmd = 'scp'
if recursive:
scp_cmd += ' -r'
scp_cmd += f' {user}@{host}:{from_dir} {to_dir}'
child = pexpect.spawnu(scp_cmd, timeout=timeout)
child.expect(['[pP]assword: '])
child.sendline(str(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
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件