通过subprocess.Popen在SSH或SCP中发送密码
我正在尝试使用 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
来轻松验证这一点。那么为什么这个方法不行呢?
需要注意的是,有很多类似的问题在讨论 subprocess.Popen
和如何发送密码以实现自动化的 SSH 或 FTP 登录:
如何通过 Python 脚本在 Linux 中设置用户密码?
使用 subprocess 发送密码
这些问题的答案不适用或者不管用,因为我使用的是 Python 3。
7 个回答
10
OpenSSH的scp
工具会调用ssh
程序来建立与远程主机的SSH连接,而ssh
进程负责身份验证。ssh
工具不接受命令行或标准输入中的密码。我认为这是OpenSSH开发者的一个故意选择,因为他们认为人们应该使用更安全的方式,比如基于密钥的身份验证。任何调用ssh的解决方案都会遵循以下几种方法:
- 使用SSH密钥进行身份验证,而不是使用密码。
- 使用sshpass、expect或类似工具来自动响应密码提示。
- 使用(滥用)SSH_ASKPASS功能,通过调用另一个命令来获取
ssh
的密码,具体描述可以在这里或这里找到,或者在一些答案中这里也有提到。 - 让SSH服务器管理员启用基于主机的身份验证并使用它。请注意,基于主机的身份验证只适合某些网络环境。更多信息可以在这里和这里找到。
- 使用perl、python、java或你喜欢的语言编写自己的ssh客户端。大多数现代编程语言都有ssh客户端库,你可以完全控制客户端如何获取密码。
- 下载ssh源代码,构建一个符合你需求的修改版
ssh
。 - 使用其他ssh客户端。还有其他ssh客户端可供选择,包括免费和商业版本。也许其中一个更适合你的需求,而不是OpenSSH客户端。
在这种情况下,考虑到你已经在python脚本中调用scp
,以下两种方法似乎是最合理的选择:
14
这里有一个用 pexpect
来通过密码进行 ssh
连接的函数:
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
也应该能做到类似的事情。
7
你链接的第二个答案建议你使用 Pexpect 这个工具(通常来说,这是与需要输入的命令行程序进行交互的正确方法)。