使用密码从命令行运行SCP

时间:2015-02-04 22:23:29

标签: python command-line centos fabric scp

我需要使用密码从命令行运行SCP。

具体来说,这是因为我需要使用Python库Fabric将一台远程计算机SCP连接到另一台远程计算机,而文件不通过本地计算机(这是一个大文件,两台远程计算机连接速度更快)除了我的本地机器之外,它们之间有任何一个。)两台远程机器正在运行CentOS。

但就主要问题而言,这些细节都不是特别重要。

1 个答案:

答案 0 :(得分:0)

首先,详细说明执行此操作的安全隐患,只需运行ps -ww -fp <pid>即可轻松查看命令行参数。此漏洞是scp不允许在命令行上传入密码的原因。

因此,请确保您可以运行该命令的任何人都能以纯文本格式查看密码。

SCP的作者认为你是如此愚蠢,以至于你会滥用在命令行上输入密码的能力。另一方面,我相信你已经被充分警告了,如果你想这样做,你就不应该被阻止。

在实际解决方案上:

您需要在应运行SCP的计算机上安装expect

在我使用Python库Fabric控制运行CentOS的机器的特定情况下,我运行以下命令来安装它:

from fabric.operations import sudo

sudo('yum -y install expect')

要直接从CentOS上的命令行运行,只需执行:

$ yum -y install expect

(我假设你知道你在自己的操作系统上与yum等价的东西。)

预计安装后,您可以像这样运行SCP:

expect -c
'spawn scp <copy-from-username>@<copy-from-address>:<copy-from-path> <copy-to-path>;
 expect "*?es??o*"   {send "yes\r"; exp_continue}
        "*?assword:" {send "<copy-from-password>\r"};
 interact'

我已将其格式化以便于阅读,但您可以使用空格替换换行符/标签,它们的工作方式也相同。

第一行表示以下是expect命令(不是其余的单引号)。

第二行产生了SCP进程。

第三行开始定义要在输出中查找的内容,并说"*?es??o*"应得到yes的响应。 \r对于发送输入击键非常重要。时髦模式旨在捕获类似(Yes/No)的内容,如果它询问是否继续建立连接。 exp_continue告诉他们在回复此邮件后仍未完成。

第四行有另一个要寻找的东西,该行中的模式旨在捕获Password:,无论p是否为大写。确保在密码后面加\r,否则将不会发送密码。此行没有exp_continue,因为一旦expect发送了密码,我们就不再需要了。

第五行interact非常重要,因为没有它就行不通。我对它究竟是做什么有点模糊,但我的理解是spawn直到那条线被击中。我想这很重要,因为你需要在运行spawn之前定义期望,否则生成的进程可能会传递任何期望的内容,这可能会破坏整个目的。这是我的理解 - 我可能是错的。无论哪种方式,脚本都可以工作。

这是我用Fabric编写的Python函数完整地执行此操作:

def putFromFileRepository(repoIP, repoUsername, repoPassword, repoPath, putPath):
    from fabric.operations import sudo

    # There are security implications from passing a password as an argument
    # on the command line, namely that command line arguments can be easily seen
    # from anywhere via 'ps -ww -fp <pid>'.
    # Thus scp doesn't allow passwords to be passed on the command line.
    # We'll install expect to make it possible.
    sudo('yum -y install expect')

    repoStr = repoUsername + '@' + repoIP + ':' + repoPath

    # expect has alien syntax - explained inline below.
    # see man expect for more details.
    sudo("expect -c 'spawn scp " + repoStr + ' ' + putPath + '; ' # Run SCP when started.
         + 'expect "*?es??o*" {send "yes\r"; exp_continue} '      # Reply yes to yes/no questions.
         + '"*?assword:" {send "' + repoPassword + '\r"}; '       # Give password when prompted.
         + "interact'")  # Start.