运行 带密码的命令行 SCP

Run SCP From Command Line With Password

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

具体是因为我需要使用Python库Fabric来让一台远程机器SCP到另一台远程机器,而不需要通过本地机器传递文件(这是一个大文件,两个远程机器之间的连接比我的本地机器与它们中的任何一个的连接都要快得多。)两台远程机器是 运行ning CentOS。

但是 none 这些细节对于主要问题特别重要。

首先,详细说明这样做的安全隐患,只需运行宁ps -ww -fp <pid>就可以很容易地查看命令行参数。这个漏洞就是scp不允许在命令行传入密码的原因。

因此,请确保您接受以下事实:任何可以 运行 该命令的人都可以看到纯文本密码。

SCP 的作者假设您愚蠢到会滥用在命令行中输入密码的能力。另一方面,我相信此时你已经得到了充分的警告,如果你想这样做,你不应该被阻止。

进入实际解决方案:

您需要在应该 运行 SCP 的机器上安装 expect

在我使用 Python 库 Fabric 来控制机器 运行ning CentOS 的具体情况下,我 运行 安装它:

from fabric.operations import sudo

sudo('yum -y install expect')

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

$ yum -y install expect

(我假设您自己知道 yum 的等价物 OS。)

安装 expect 后,您可以 运行 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'

我已经对其进行了格式化以使其更易于阅读,但是您可以将 linebreaks/tabs 替换为空格,它仍然可以正常工作。

第一行说下面是一个期望命令(不是其余的单引号)。

第二行生成 SCP 进程。

第三行开始定义要在输出中查找的内容,并表示 "*?es??o*" 应该得到 yes 的响应。 \r 对于发送回车键很重要。时髦的模式旨在捕获类似 (Yes/No) 的内容,例如,如果它询问是否继续建立连接。 exp_continue 告诉 expect 回复此消息后还没有完成。

第四行还有另一件事要寻找,该行中的模式旨在捕获 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.