我想将单个文件从远程服务器复制到本地机器。
我没有远程机器的 root 权限,但我可以成功地通过 SSH 连接到给定密码的用户。
然而,在实际复制任何内容之前,连接就被关闭了。
这是我尝试过的:
scp -P PORT user@SRC_HOST:/tmp/file /home/k4mp3t/
使用详细模式我得到以下输出:
debug1: Next authentication method: password
Authenticated to HOST.IP ([IP]:PORT) using "password".
debug1: channel 0: new [client-session]
debug1: Requesting [email protected]
debug1: Entering interactive session.
debug1: pledge: filesystem
debug1: Sending subsystem: sftp
scp: Connection closed
debug1: client_input_channel_req: channel 0 rtype exit-signal reply 0
debug1: client_input_channel_req: channel 0 rtype [email protected] reply 0
debug1: channel 0: free: client-session, nchannels 1
Transferred: sent 2896, received 3328 bytes, in 0.1 seconds
Bytes per second: sent 36199.5, received 41599.5
debug1: Exit status -1
scp连接为什么关闭了?
有关远程机器的信息:
ssh -V
OpenSSH_5.5p1 Debian-6+squeeze2, OpenSSL 0.9.8o 01 Jun 2010
有关我的机器的信息:
ssh -V
OpenSSH_9.0p1, OpenSSL 1.1.1q 5 Jul 2022
OS: EndeavourOS Linux x86_64
Host: VirtualBox 1.2
Kernel: 5.18.14-arch1-1
Shell: bash 5.1.16
我将非常感谢任何可以帮助我解决此问题的帮助或资源。
答案1
总结
尝试scp -O
,例如:
scp -O -P 1234 user@server:/tmp/file /home/k4mp3t/
分析
输出的这个片段:
debug1: Sending subsystem: sftp scp: Connection closed
告诉我您的本地scp
尝试使用 SFTP 协议。传统scp
使用不同的 SCP 协议。scp
在这种情况下,您的不是传统的。
历史、SCP 和 SFTP
多年来scp
(可执行文件)一直默认使用 SCP(协议),而不了解任何其他协议。我喜欢称 SCP 为“一种坚持不懈的黑客行为”。要通过 SCP 与远程系统通信,本地系统scp
会调用ssh
并传递命令。命令(就像任何通过的命令一样ssh
) 由远程用户的 shell 解释。该命令尝试scp
在远程端运行,使用未记录的选项将man 1 scp
其转变scp
为服务器。远程文件的名称嵌入在 shell 代码中。如果一切正常,本地scp
和远程scp
最终将相互通信并传输数据。
不幸的是,这是脆弱的;有些事情很容易破坏或滥用该协议:
如果你需要引用或转义将在远程端使用的路径名,则需要引用或转义本地 shell 和分别地对于远程 shell;即您需要两级引用/转义。一方面,这允许您在远程端使用通配符,例如,本地引用的
*
可能在远程端被取消引用并被扩展那里另一方面,如果你真的需要引用,并且你不知道这些东西是如何工作的,你很容易就会犯一个错误的命令(例子)。如果您知道如何操作,或者不幸误操作(可能是因为引用错误,见上文),您实际上可以在远程端运行任意代码。换句话说,您可以传递一个“远程路径名”,远程 shell 会将其解释为 shell 代码(例子)。这实际上不是一个安全漏洞,因为
ssh
无论如何你都可以通过它运行相同的代码(毕竟这是你的本地scp
为你做的)。问题在于潜在的将某些东西作为代码运行的能力无意中。服务器可能会给你提供你没有请求的文件,而你的本地文件
scp
可能会接受它们(取决于你使用的实现和版本,请参阅这个答案)。如果远程“shell”实际上不是 shell(或者它是与 POSIX shell 不兼容的 shell
sh
),那么即使是简单、安全的命令也可能会失败。这可能包括您本地scp
创建的任何命令。远程 shell 可能会在执行命令之前运行某些操作(例子)。如果这涉及到打印到 stdout(即最终到本地
scp
)或从 stdin 读取(即最终从本地scp
),则本地scp
将失败(例子)。如果远程端没有将 识别为命令,则不支持 SCP。如果远程端
scp
没有可执行文件,或者远程用户的 shell 中不包含远程 的目录,则会发生这种情况。scp
$PATH
scp
SFTP 是一种设计更好的协议。它肯定解决了 (1) 和 (2),我相信它解决了 (3)。在服务器端,它可以使用通过远程用户的 shell 调用的单独可执行文件,因此 (4) 和 (5) 仍然是问题;适当的配置可以使其独立于用户的 shell $PATH
,因此 (6) 得到解决。或者它可以使用Subsystem sftp internal-sftp
(in sshd_config
),然后 (4) 和 (5) 得到解决(甚至可以修复远程用户损坏的启动脚本)。
SFTP 比 SCP 更好,但sftp
(可执行文件)并不总是比 更好scp
。sftp
在交互上工作得很好,而的语法scp
类似于的语法cp
(你甚至可以scp a b
喜欢cp a b
;scp
只需回到cp
本地复制,对于某些人来说功能错误)。如果您想使用其中一个来以非交互方式(例如在脚本中)简单地传输几个文件,那么您可能会使用scp
看起来更直接的那个。
现在你可以使用scp
SFTP 代替 SCP。OpenSSHscp
的 Modern 默认使用 SFTP。从变更日志:
OpenSSH 9.0 于 2022-04-08 发布。 […]
[…]
此版本
scp(1)
默认从使用旧的 scp/rcp 协议切换到使用 SFTP 协议。
回到你的案子
您的scp
服务器显然是现代的,并且默认使用 SFTP。但是,相关服务器不支持相关子系统。通常禁用它很简单,只需注释掉以下Subsystem sftp …
行。但是我期望subsystem request failed
;你得到的是connection closed
,所以可能不完全是这样。但出于某种原因,SFTP 仍然无法与此服务器配合使用。
解决方案
强制你scp
使用 SCP。来自man 1 scp
:
-O
使用旧版 SCP 协议而不是 SFTP 协议进行文件传输。对于未实现 SFTP 的服务器、为了向后兼容特定的文件名通配符模式以及为了使用~
旧版 SFTP 服务器的前缀扩展路径,可能需要强制使用 SCP 协议。
该命令如下:
scp -O …
请记住,这将使用 SCP 及其所有特性。
兼容性注意事项
即使您知道自己想要 SCP,一般来说也不能scp -O …
盲目使用。对 SFTP 一无所知的实现或版本scp
将无法识别-O
,因此它们会失败。我知道您scp
可以使用-O
;它尝试使用 SFTP,因此它必须支持-O
。但如果您尝试从旧系统使用一些旧版本进行相同的传输,scp
则必须省略-O
。
您的原始问题表明您需要知道服务器支持哪些协议。我的观点是还需要了解您所在地区scp
支持哪些协议和选项。
要将文件传输到相关服务器或从相关服务器传输文件:
scp
没有的现代版本-O
无法工作(因为服务器不支持 SFTP),但应该可以工作-O
;- 但是旧的
scp
不能工作-O
(因为它不识别该选项),它应该可以在没有的情况下工作-O
; - 并且我遇到过默认
scp
使用(并提供强制 SFTP)的情况;这个应该可以与没有显式的一样工作。-O
-s
-O
-O
scp
结论是:如今如果您想使用 SCP,那么没有通用的语法。