zpa*_*win 9 ssh scp openssh sshd
ssh
&scp
在我的台式机和笔记本电脑上工作。从我的 Android 手机上的 termuxssh
可以运行,但scp
不能运行。在这种情况下,我收到有关“连接已关闭”的错误。
最初,当我问这个问题时,我在连接到我的 Fedora Linux 盒子时在 Android 手机上从 termux 运行 scp 时遇到了这个问题。我很困惑,因为ssh
一直在工作,所以我提供了很多调试信息。由于我后来了解到这个问题与 termux 完全无关,而与 OpenSSH 版本无关,因此我尝试清理大量无关的信息转储并使其更易于访问,同时仍然保留相关错误消息以实现更好的 seo 匹配。
计算机 A 和 B 具有基本相同的sshd_config
文件,所有 3 台计算机的文件内容基本相同~/.ssh/config
。
A->B、B->A、C->A 和 C->B 之间的 ssh 连接都工作正常。我对从任何一台计算机连接到我的手机不感兴趣,并且从未在其上配置 sshd,因此没有测试该场景。
但是,对于通过 ssh 运行的 scp,我遇到了以下情况:A->B 和 B->A 工作,而 C->A 和 C->B 失败并出现以下错误:
$ scp -rp "desktop-user@192.168.1.123:/home/desktop-user/Pictures/test.jpg" .
scp: Connection closed
Run Code Online (Sandbox Code Playgroud)
~/.ssh/config
设置等。没有明显的问题。~/.ssh/config
定义。不用找了。scp
带有-v
标志的命令来提供详细的调试信息。在编辑哈希值等之后,我添加到了Pastebin。我看到的主要事情是密钥似乎被接受,但最后一行表明“debug1:退出状态 127”。在线结果似乎表明scp
主机上不存在......但就我而言,它是。所以还是没有改变。同样,A 和 B 的配置基本相同
# grep -Pv '^\s*(#|$)' /etc/ssh/sshd_config
Include /etc/ssh/sshd_config.d/*.conf
Port 22
Ciphers aes256-gcm@openssh.com,aes256-ctr
LoginGraceTime 1m
PermitRootLogin no
MaxAuthTries 4
MaxSessions 6
PermitEmptyPasswords no
ChallengeResponseAuthentication no
UsePAM yes
X11Forwarding yes
PrintMotd no
UseDNS yes
AcceptEnv LANG LC_*
Subsystem sftp /usr/lib/openssh/sftp-server
Protocol 2
DenyUsers root docker-user
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-512,hmac-sha2-256-etm@openssh.com,hmac-sha2-256
KexAlgorithms diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256
Run Code Online (Sandbox Code Playgroud)
zpa*_*win 15
更新:对于那些只想快速了解并阅读最少内容的人。
\n知道:
\nsftp
在紧要关头可以工作,但它处理符号链接复制的方式与此不同,scp
因此不要只是将其作为替代品放入脚本中。更好用rsync
。递归地将目录从远程复制到本地:
\n# deprecated / insecure (see CVE link below) but works\nscp -O -rp -P <port> "<user>@<host_ip>:<SRC_PATH>" "<DST_PATH>"\n \n# secure / recommended by openssh - also works\nrsync -saLPz --port <port> -e ssh "<user>@<host_ip>:<SRC_PATH>" "<DST_PATH>"\n
Run Code Online (Sandbox Code Playgroud)\n递归地将目录从本地复制到远程:
\n# deprecated / insecure (see CVE link below) but works\nscp -O -rp -P <port> "<SRC_PATH>" "<user>@<host_ip>:<DST_PATH>"\n \n# secure / recommended by openssh - also works\nrsync -saLPz --port <port> -e ssh "<SRC_PATH>" "<user>@<host_ip>:<DST_PATH>"\n
Run Code Online (Sandbox Code Playgroud)\n这也适用于多路径,例如
\n# copy multiple paths\nrsync -saLPz --port <port> -e ssh "<SRC_PATH_1>" "<SRC_PATH_2>" "<SRC_PATH_3>" "<user>@<host_ip>:<DST_PATH>"\n \n# copy multiple paths from array\narrPaths=("<SRC_PATH_1>" "<SRC_PATH_2>" "<SRC_PATH_3>");\nrsync -saLPz -e ssh "${arrPaths[@]}" "<user>@<host_ip>:<DST_PATH>"\n
Run Code Online (Sandbox Code Playgroud)\n经过大量的在线搜索后,我终于在这里找到了答案- 感谢/感谢 manjaro 论坛用户 zbe 和 canyue980 找到了最初的修复程序并让我了解实际发生的情况。
\n引用canyue980的话:
\n\n\n感谢所有提供帮助的人!我刚刚在上面的链接中找到了解决方案:
\n\n\n注意:自 OpenSSH 8.8 起,scp 实用程序默认使用 SFTP 协议。必须使用 -O 选项才能使用旧版 SCP 协议。
\n通过使用 -O 选项,它可以工作\xef\xbc\x81
\n\n\nscp -O 文件名 目标目录
\n当然你也可以在~/.zshrc中为它添加一个别名,如下所示:
\n\n\n别名 scp="scp -O"
\n
事实上,我的命令从:
\nscp -rp -P 1234 "desktop-user@192.168.1.123:/home/desktop-user/Pictures/test.jpg" .\n
Run Code Online (Sandbox Code Playgroud)\n到:
\nscp -rpO -P 1234 "desktop-user@192.168.1.123:/home/desktop-user/Pictures/test.jpg" .\n
Run Code Online (Sandbox Code Playgroud)\n它的效果就像冠军一样。将保留这一点,希望对其他人有帮助。
\n使用的安全影响-O
(在旧版本中是“哦” - 不是零):根据openssh 8.8 的发行说明,听起来主要风险是:
\n\n旧版 scp/rcp 通过远程 shell 执行远程文件名的通配符扩展(例如\n“scp host:* .”)。这会产生副作用,\n需要在 scp(1) 命令行中包含的文件名中\n对 shell 元字符进行双引号,否则它们可能会被解释\n为远程端的 shell 命令。
\n
我个人并不认为这对于习惯旧命令并手动运行或通过家庭计算机上的受信任脚本运行的人来说是一个很大的风险。但您的风险评估/用例可能会有所不同 - 特别是对于使用未经验证/不受信任的脚本的业务系统或设置。对于某些人来说似乎就是这种情况,因为RHEL 9 正在弃用 scp 协议,理由是:
\n\n\n我们做出这一改变是因为 SCP 协议已有数十年历史,并且存在多种安全风险和问题,且没有直接的解决方案。新问题经常被报告(CVE-2020-15778是撰写本文时最新的问题,但我们不能确定这将是最后一个),并且正确修复它们相当困难,因为协议本质上是经过身份验证的会话值得信赖的。
\n
从上面的发行说明和链接以及arch wiki上的说明来看,其意图似乎是完全弃用SCP(例如协议),转而采用诸如sftp
和 之类的替代方案rsync
(见下文)。我不清楚该scp
司令部的未来打算是什么的预期未来是什么,尤其是在短期内,但它似乎有可能甚至可能在未来被弃用。
要在脚本中使用sftp
和rsync
作为直接替换,可能rsync
是更容易的直接替换,因为它不需要在主机上进行任何更改,而至少从 Fedora 35 开始sftp
是这样。
sftp
只要您可以sftp <user>@<host_ip>
像使用一样连接,下面的命令就应该有效ssh
(以这种方式连接将使您进入sftp
“shell”。要退出,请使用exit
)。否则,您可能必须在主机上启用它。对于 Fedora 35,该过程如下:
sudo cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.$(date +\'%F_%T\').bak
sudo sed -Ei \'s~^(Subsystem[ \\t]+sftp[ \\t]+)(/usr/lib/openssh/sftp-server)~#\\1\\2\\n\\1internal-sftp~g\' /etc/ssh/sshd_config
sudo systemctl restart sshd
完成后,您应该看到类似这样的内容(例如,sftp 服务器行应被注释掉,并添加一个带有 internal-sftp 的新行来取代它的位置):
\nsudo grep Subsystem /etc/ssh/sshd_config\n#Subsystem sftp /usr/lib/openssh/sftp-server\nSubsystem sftp internal-sftp\n
Run Code Online (Sandbox Code Playgroud)\n如果您需要增强安全性,您还可以使用组和 chroot 来限制此操作,如此处和此处所示。
\n注意:scp
默认情况下复制符号链接的内容而不是作为符号链接。Rsync 允许您通过使用-l
复制为符号链接或-L
复制符号链接引用的内容来控制此行为。(archive)选项-a
将默认为-l
,除非-L
也指定了。会将符号链接复制为链接(例如,不sftp
复制指向的内容),并且截至撰写本文时不提供控制此行为的选项。您可以通过分别查看和下选项的文档来验证这一点。-r
man scp
man sftp
以下是一些大致等效命令的示例,这些命令都应该通过 SSH 并获取您的~/.ssh/config
设置和身份:
递归地将目录从远程复制到本地:
\nscp -O -rp -P <port> "<user>@<host_ip>:<SRC_PATH>" "<DST_PATH>"\n \nrsync -saLPz --port <port> -e ssh "<user>@<host_ip>:<SRC_PATH>" "<DST_PATH>"\n
Run Code Online (Sandbox Code Playgroud)\n递归地将目录从本地复制到远程:
\nscp -O -rp -P <port> "<SRC_PATH>" "<user>@<host_ip>:<DST_PATH>"\n \nrsync -saLPz --port <port> -e ssh "<SRC_PATH>" "<user>@<host_ip>:<DST_PATH>"\n
Run Code Online (Sandbox Code Playgroud)\n编辑:2022 年 9 月 13 日:今天在重新测试时注意到我所执行的命令sftp
给出了错误,因此我将它们从上面移出并添加了一些免责声明。我个人并不推荐sftp
作为替代品,scp
因为我上面提到的在涉及符号链接时它们如何处理复制方面存在差异。
我对使用它作为脚本中的替代品特别感兴趣。如果您只需要交互模式,不介意为 制作“批处理”指令文件sftp
,或者已经rsync
安装在您将使用的所有计算机上,那么您可能不需要走这么远。我下面的笔记部分基于这个答案,并由我完成了一些额外的测试。
我在这里最大的抱怨(除了sftp
使用不同的上传和下载语法之外)是非常糟糕的文档。查看,语法根本man sftp
没有记录(这意味着虽然该工具可以非交互方式使用,但仅记录了在批处理和交互模式下使用的情况,并且尽管支持但不支持跨出这些用例)记录)。手册页没有提供常见用法的示例,甚至没有像许多 GNU 工具那样提供更详细文档的网站。并且提供了少于手册页。从字面上看,如果没有搜索引擎和这样的网站,我就会完全放弃sftp -h
sftp
作为一种选择。
1.本地拉取(例如从本地终端,将文件从远程下载到本地)
\n这大多是直接的,并且工作原理与scp
除了上面提到的差异(例如符号链接)和稍微不同的语法之外,其工作原理有些相似。其中一种变体将导致交互式提示。
# Download a single file with same name to current dir\nsftp -pC -P <port> "<user>@<host_ip>:<SRC_PATH>"\n# or\nsftp -pC -P <port> "<user>@<host_ip>:<SRC_PATH>" .\n \n# Download a single file to name and path in "<DST_PATH>"\nsftp -pC -P <port> "<user>@<host_ip>:<SRC_PATH>" "<DST_PATH>"\n \n# Download a folder and all of its contents,\n# keep the same name as the remote and save to current dir\n# note that any symlinks will copy only the symlink itself\n# and NOT the data the link references\nsftp -rpC -P <port> "<user>@<host_ip>:<SRC_PATH>" .\n \n# Now if you omit "<DST_PATH>" entirely like you can with\n# the single-file version (first command in this code-block)\n# you instead drop to an interactive prompt and have to type\n# type \'exit\' to get back to your bash prompt\n# e.g. AVOID THIS IN NON-INTERACTIVE SCRIPTS!!!\nsftp -rpC -P <port> "<user>@<host_ip>:<SRC_PATH>"\nConnected to <host_ip>.\nChanging to: <SRC_PATH>\nsftp> \nsftp> exit\n \n# Download a folder and all of its contents,\n# to name and path in "<DST_PATH>"\n# note that any symlinks will copy only the symlink itself\n# and NOT the data the link references\nsftp -rpC -P <port> "<user>@<host_ip>:<SRC_PATH>" "<DST_PATH>"\n
Run Code Online (Sandbox Code Playgroud)\n2.本地推送(例如从本地终端,将文件从本地上传到远程)
\n首先,如果您只是尝试反转参数,就像我原来的答案一样,那么您将收到连接错误。为什么sftp
上传语法与下载语法不一致?你的猜测和我的一样好……我本人就是这种方法的忠实粉丝。但如果你尝试一下,会发生以下情况(注意:此输出来自两台运行 Fedora 35 且正确配置了 ssh 的机器,并且scp
工作rsync ... -e ssh
正常,并且不会提示进行身份验证)。
# single file\nsftp -pC -P <port> test.txt "<user>@<host_ip>:<DST_PATH>"\nssh: Could not resolve hostname test.txt: Name or service not known\nConnection closed. \nConnection closed\n\n# dir\nsftp -rpC -P <port> "<SRC_PATH>" "<user>@<host_ip>:<DST_PATH>"\nssh: Could not resolve <SRC_PATH>: Name or service not known\nConnection closed. \nConnection closed\n
Run Code Online (Sandbox Code Playgroud)\n根据我上面链接的答案,正确的方法如下
\n# push a single file from local to remote\nsftp -pC -P <port> "<user>@<host_ip>:<DST_PATH>" <<< \'put test.txt\'\n# or\necho \'put test.txt\' | sftp -pC -P <port> "<user>@<host_ip>:<DST_PATH>"\n\n# push a entire dir (and its contents) from local to remote\n# notice the inner single quotes to escape <SRC_PATH>\n# for enclosing paths containing whitespace\nsftp -rpC -P <port> "<user>@<host_ip>:<DST_PATH>" <<< "put \'<SRC_PATH>\'"\n# or\necho "put \'<SRC_PATH>\'" | sftp -rpC -P <port> "<user>@<host_ip>:<DST_PATH>"\n# or\nprintf \'put "%s" "%s"\\n\' "<SRC_PATH>" "<DST_PATH>" | \\\nsftp -rpC -P <port> "<user>@<host_ip>"\n
Run Code Online (Sandbox Code Playgroud)\n我在我的脚本中发现使用类似的语法进行下载,例如
\n# pull a entire dir (and its contents) from remote to local\n# notice the inner single quotes to escape <SRC_PATH>\n# for enclosing paths containing whitespace\nprintf \'get "%s" "%s"\\n\' "<SRC_PATH>" "<DST_PATH>" | \\\nsftp -rpC -P <port> "<user>@<host_ip>"\n
Run Code Online (Sandbox Code Playgroud)\n不太令人困惑,但以上所有内容都应该有效。
\n要一次复制多个路径,可以使用数组(或者您可以创建一个批处理文件,put
在单独的行上列出每个命令并将其传递给sftp
使用-b <batchfile>
选项)。
# copy multiple paths from array\narrPaths=("<SRC_PATH_1>" "<SRC_PATH_2>" "<SRC_PATH_3>");\nprintf \'put %s\\n\' "${arrPaths[@]}" | sftp -rpC -P <port> "<user>@<host_ip>:<DST_PATH>"\n
Run Code Online (Sandbox Code Playgroud)\n2022 年 10 月 10 日更新:在遇到rsync
包含空格的副本的一些问题后,我更新了命令以使用该-s
选项(在此答案中进行了解释)
然而,我注意到 rsync 与scp
and的不同之处sftp
(在处理空格方面)是,scp
对于包含内部引号的路径总是很好,例如
scp -rp "remoteuser@remotehost:\'/tmp/rsync-test/stuff from server/the data.txt\'" "."\n
Run Code Online (Sandbox Code Playgroud)\n然而,如果你在 中这样做rsync
,你会得到一个错误:
$ rsync -saXULz --progress -e ssh \\\n "remoteuser@remotehost:\'/tmp/rsync-test/stuff from server/the data.txt\'" "."\n \nreceiving incremental file list\nrsync: [sender] change_dir "/home/remoteuser/\'/tmp/rsync-test/stuff from server" failed: No such file or directory (2)\nrsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1839) [Receiver=3.2.5]\nrsync: [Receiver] write error: Broken pipe (32)\n
Run Code Online (Sandbox Code Playgroud)\n解决这个问题非常简单,但如果您像我一样习惯使用内部引号路径语法,则可能不直观scp
:只需使用-s
并删除内部引号。rsync
足够聪明来处理它并且它确实有效。
所以上面的命令有错误,只需更改为:
\n$ rsync -saXULz --progress -e ssh \\\n "remoteuser@remotehost:/tmp/rsync-test/stuff from server/the data.txt" "."\n
Run Code Online (Sandbox Code Playgroud)\n一切都应该很好(假设scp
在同一路径上工作正常)。