嗯,不完全是。这更像是黑客攻击。或者是两个协议的未记录的、非标准化的混搭。让我们来看看令人兴奋(和可怕)的细节。
安全复制协议(SCP)允许我们在两台计算机之间移动文件(和目录)。使用它很简单:
这会将local_file.txt复制到另一台域名为remote_host的计算机(通常是服务器)的/home目录中。
它的美妙之处在于,它可以在几乎所有类Unix系统和许多流行的Windows客户端上运行!这种无处不在的可用性和易用性是SCP如此出名的原因。而且很容易建立一个关于它是如何工作的心理模型,这在故障排除时很有帮助。
但是移动文件并不是那么令人兴奋。SCP的真正价值在于对两台计算机进行身份验证和对运行中的数据进行加密(这就是“S”表示的)。
在使用它时,您可能已经注意到,您需要首先设置对远程计算机的SSH访问。SCP身份验证提示甚至看起来与SSH完全一样。这是因为SCP运行在SSH之上-它将SSH用作明文文件数据的管道。事实上,SSH完成了上面描述的所有安全繁重任务,SCP只通过SSH连接抛出一些明文文件。
这篇维基百科条目有一些SCP历史。简而言之:在旧的BSD系统上曾经有一个名为RCP的工具,它可以在计算机之间移动文件。这是在值得信赖的网络无忧无虑的日子里,每个人都是其他人的朋友。然后人们意识到,也许并不是他们网络上的每个人都是这样的好朋友。有人将RCP实现复制到OpenSSH的前身,并简单地在SSH会话上运行它,以保护文件不受非好友的影响。问题解决了!从那以后,它一直保留在OpenSSH中,许多其他软件为了兼容而模仿它,所以我们就在这里。
SSH RFC相当简单和完整。但是没有任何关于通过SSH复制文件的内容。那么SCP是如何实施的呢?
SCP不是标准化协议。没有关于如何实现它的RFC或任何官方描述。OpenSSH实现是事实上的“规范”。这个实现分为两个部分:“连接”建立和之后的有线协议。
好吧,这不是真正的联系。它只是使用SSH执行的命令的STDIN/STDOUT,有点像Unix管道。OpenSSH有两个主要程序参与其中:sshd和scp。sshd是始终运行的服务器守护进程,接受新的SSH连接。scp是一个客户端程序,它伪装成ssh,然后发送或接收文件。
当SCP程序运行时,它会打开一个新的SSH连接。在该连接上,它在服务器端执行另一个SCP程序,带有特殊的、未记录的标志。您可以将scp视为运行ssh exec scp[FLAGS]。主要标志是-t(“to”)和-f(“from”),分别用于接收和发送,其他标志是-d(目标是目录)和-r(递归的,源是目录)。
值得注意的是,SCP协议是单向的:一端是发送文件,另一端是接收。要走另一条路,您需要单独的SCP执行。
SCP在远程端运行后,实际的SCP协议命令开始通过STDIN和STDOUT流动。
现在,我们有了安全的I/O管道,并有效地切换到RCP协议。该协议是顺序的(一次一个操作)和同步的(每个命令必须在下一个命令开始之前完成)。
[参数]是特定于命令的,如文件/目录名、文件大小或时间戳。“E”命令没有参数。
当最后一条命令为‘C’(创建文件)时发送[可选数据]。数据大小被指定为‘C’的参数
此外,还有控制字节,它们自己发送,没有换行符:
0x00-“OK”,确认完成最后一条命令(就像写入本地文件一样)。这也是由接收方在启动时发送的,以让发送方知道它已准备好接收命令。
0x01-“警告”,后跟要向用户显示的行(以换行符结尾)。
0x02-带有可选消息(与警告相同)的“ERROR”,但连接随后被终止。
这个带注释的示例(#符号之后的所有内容都不在协议中)应该会阐明整个过程:
到目前为止,SCP听起来还不错。粗糙的设计和缺乏规范是不幸的,但它是一个足够简单的工具,似乎可以为很多人工作。但现在让我们来看看一些现实世界的问题。
有线协议的顺序性质(每个命令都必须确认)增加了大量开销。例如,如果单个确认数据包在传输过程中被丢弃,则整个连接将暂停,直到重新传输开始。最重要的是,在不压缩的情况下发送所有数据或询问接收方是否已经拥有该文件并不理想。
经验丰富的sysadmin会告诉您,压缩文件并发送单个大型存档比使用递归scp命令要快得多。事实上,您完全可以在没有SCP的情况下做到这一点:
#复制包含10000个文件的本地文件夹$FIND/TMP/BIG_Folder/-TYPE f|wc-l10000#使用scp$time scp-r-q/tmp/BIG_Folder/server:/tmp/big_folder__Executed in 882.99 MILIS FISH外部用户时间114.09 MILIS 0.00微秒。114.09毫秒系统时间278.46毫秒949.00微秒277.51毫秒#在ssh$time上使用tar sh-c";tar cf-/tmp/BIG_Folder|ssh服务器';tar xc/tmp/-f-';";tar:删除前导';/';来自会员names__Executed的215.68毫米鱼外部使用时间93.22毫秒0.00微秒93.22毫秒系统时间66.51毫秒897.00微秒65.62毫秒。
在这个示例中,从882.99ms到215.68ms,这是4倍的加速(诚然,对于SCP来说是最糟糕的情况)!
SCP运行在SSH之上,所以它是完全安全的,对吗?哦,我可爱的夏日孩子,事情从来都不安全。
SCP协议过时、僵化、不易修复。我们建议使用更现代的协议(如sftp和rsync)进行文件传输。
如果远程端的shell打印出非交互会话的任何内容,您的本地SCP进程将很乐意将该输出解释为SCP命令。充其量,这将中断SCP协议并产生模糊错误。在最坏的情况下,远程外壳启动脚本是恶意的,它会向您发送利用漏洞的有效负载,而不是您想要的文件。
那么实现错误又是怎么回事呢?早在2018年,Harry Sintonen就在流行的SCP实现(包括OpenSSH)中发现了一系列漏洞。其中包括修改目录上的权限、覆盖任意文件(由于~/.ssh/Authorized_key或~/.bashrc而有效地执行代码),以及插入终端转义序列以隐藏任何痕迹。对于构建网络CLI应用程序的任何人来说,这些漏洞都是一个很好的教训。
好吧,那么也许SCP终究还是有问题的。我们应该如何在不设置全新系统或求助于蜗牛邮寄USB驱动器的情况下在计算机中移动文件?
SFTP被广泛认为是SCP的继任者。它仍然在SSH之上运行,以实现传输层安全性,并且不需要单独设置访问。它可以为您提供浏览远程文件系统的自定义交互式提示,或者您可以使用预先编写的一系列命令编写脚本。
不利的一面是,您需要学习SFTP提示符命令,并且协议本身还没有完全标准化(有很多RFC草案,但作者最终放弃了)。
rsync是另一个很好的选择。其用法与scp命令完全相同-它是也利用SSH的临时替代命令。rsync完全取决于性能-它在本地执行大量复杂的计算,以便通过网络发送尽可能少的数据。从技术上讲,它进行数据同步而不是纯传输-如果远程和本地内容相似,则只发送增量。
同样,它也有自己的缺点:发送方使用大量的CPU能力来确定要发送什么,而接收方使用大量的磁盘IO来按正确的顺序将东西组合在一起。与OpenSSH不同,大多数系统上也没有预装rsync。
如果您需要将文件发送给某人(而电子邮件不是一个选项),Magic Wormhole是一个简单易用的工具。您可以在带外(如通过电话)交换简短、可读的代码,并附加一些文件。它可以处理典型的NAT穿越难题,并且比交换SSH密钥容易得多。
问题是每次传输都需要交换验证码,所以只适用于一次性拷贝。整个系统都是为人类设计的,如果你需要在你的笔记本电脑和一些服务器之间传输数据,魔术虫洞不是合适的工具。
更重要的是,还有在个人设备(包括手机和服务器)之间同步文件夹的软件。Syncthing和PerKeep就是两个很好的例子。这些系统总是在后台运行,并在文件之间交换差异,类似于rsync。
两者都需要一些时间来学习和配置(特别是在您利用它们的许多功能的情况下),并且主要针对个人数据(如照片或聊天日志)进行优化,而不是针对基础架构脚本进行优化。它们也比我上面提到的所有东西都慢得多,也更需要资源。
SCP是一个实现古怪的简单工具。它在移动文件方面做得不错,但较新的软件在很多方面都优于它。SCP仍然适用于您信任的计算机之间的简单个人用例。它很熟悉,一直在那里等着你。
但是,如果您有性能问题或需要满足更高的安全标准,上面列出的任何替代方案都比SCP更可取。选择最适合您需要的,然后迁移过来。