如何在命令行中强制SSH接受新的主机指纹?

130

我正在获取标准内容

WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that the RSA host key has just been changed.
The fingerprint for the RSA key sent by the remote host is

错误信息。但是执行命令的系统(Appworx)是自动化的,我无法轻易接受新密钥,即使在与第三方供应商确认更改有效性后也是如此。我可以添加一个新的 shell 脚本,可以从同一系统(和用户)执行,但似乎没有命令或命令行参数可以告诉 ssh 接受该密钥。我在手册页或 Google 上找不到任何信息。这肯定是可能的吧?

9个回答

153

这里的答案都是糟糕的建议。在任何真实世界的系统中,您都不应该关闭StrictHostKeyChecking(例如,如果您只是在自己的本地家庭网络上玩耍,那么可能还可以 - 但对于其他任何事情都不要这样做)。

相反,请使用:

ssh-keygen -R hostname

或者如果没有使用默认端口22:

ssh-keygen -R '[hostname]:port'

这将强制更新known_hosts文件,以删除已更新其密钥的仅一个服务器的旧密钥。

然后当您使用:

ssh user@hostname

它会要求您确认指纹-就像对于任何其他“新”的(即以前未见过的)服务器一样。


10
请注意:这是唯一正确的答案!例如,在本地开发Docker容器上使用"StrictHostKeyChecking no",因为每次更新镜像时,容器会更改其主机密钥,但不要在生产服务器上使用它!真的,你不希望那样做! - Mark van der Sanden
9
这段描述了交互式添加密钥的过程。因此,这并不是唯一的答案,因为你可以提供实际的密钥。这样更好,因为你使用的是已知好的副本。它还允许自动化。 - Peter Westlake
7
您还可以使用StrictHostKeyChecking accept-new以接受新密钥,但在保存的密钥冲突时仍拒绝连接。 - Chris Adams
1
@RadonRosborough MITM攻击者将能够读取脚本中的指令和数据。他们还将能够测试密钥的限制程度。最好更新known_hosts:ssh-keyscan $target_host >> ~/.ssh/known_hosts。问题太容易解决了,没有理由不这样做。 - Jeter-work
@cregox - 禁用 StrictHostKeyChecking 将禁用验证系统是否真的是您要连接的系统。通过操纵 DNS 等方式,将某人引导到仿冒服务器相对容易,这可能被用于窃取凭据等行为。这本质上与浏览器的 HTTPS / TLS 相同 - 它不仅保护连接,还验证了 wenserver 确实是 your_bank.com 等。 - AJ Poulter
显示剩余5条评论

100

虽然通常的智慧是不要禁用主机密钥检查,但SSH本身有一个内置选项可以做到这一点。由于它是新的(在Openssh 6.5中添加),所以它相对未知。

使用-o StrictHostKeyChecking=accept-new来实现。

警告:仅在您绝对信任要SSH连接的IP或主机名时使用此选项:

ssh -o StrictHostKeyChecking=accept-new mynewserver.example.com
请注意,StrictHostKeyChecking=no将公钥添加到~/.ssh/known_hosts,即使密钥已更改也会添加公钥。 accept-new仅适用于新主机。从man page中了解更多信息:如果将此标志设置为“accept-new”,则ssh将自动将新主机密钥添加到用户已知主机文件中,但不允许连接到具有更改的主机密钥。 如果将此标志设置为“no”或“off”,则ssh将自动将新主机密钥添加到用户已知主机文件中,并允许连接到具有更改的主机密钥的主机进行连接,但受某些限制。 如果将此标志设置为“ask”(默认值),则仅在用户确认他们确实要执行此操作后,才将新主机密钥添加到用户已知主机文件中,并且ssh将拒绝连接其主机密钥已更改的主机。在所有情况下都会自动验证已知主机的主机密钥。 -o StrictHostKeyChecking=no为何是恶意的?当您不检查主机密钥时,可能会在不同计算机上降落SSH会话(是的,在IP劫持的情况下是可能的)。您不拥有的恶意服务器也可以用来窃取密码和各种数据。接受新的未知密钥也非常危险。只有在对网络或服务器的绝对信任或服务器未被攻击时才应这样做。个人而言,我仅在使用cloud-init在云环境中启动机器后立即使用此标志。

3
accept-new 仅适用于新主机,而不适用于主机密钥已更改的情况 - 这就是这个问题所涉及的内容。 - Matthias Weiler
在 Docker 中,我遇到了这个错误:命令行第0行:不支持选项“accept”。 - JRichardsz
这是哪个Docker镜像?你是如何调用命令的? - oz123
在OpenSSH 7.4中不支持"accept-new"。 - Otheus
你使用的是哪个Linux发行版来提供那个版本的?OpenSSH 7.4于2016年12月19日发布。 - oz123

63

这里是告诉客户如何信任密钥。更好的方法是提前将其给客户端,在第二段中已经描述过。这适用于Unix上的OpenSSH客户端,因此我希望它与您的情况相关。

您可以设置StrictHostKeyChecking参数。它有yesnoask选项。默认为ask。要在系统范围内设置,请编辑/etc/ssh/ssh_config;要仅适用于您,请编辑~/.ssh/config;要为单个命令设置,请在命令行上给出选项,例如:

ssh -o "StrictHostKeyChecking no" hostname
如果您可以访问远程系统的主机密钥,则另一种方法是将它们提前添加到您的 known_hosts 文件中,这样 SSH 就知道它们并且不会询问该问题。从安全角度来看,如果可能的话这更好。毕竟,警告可能是正确的,您确实可能会遭受中间人攻击。
例如,以下脚本将检索密钥并将其添加到您的 known_hosts 文件中:
ssh -o 'StrictHostKeyChecking no' hostname cat /etc/ssh/ssh_host_dsa_key.pub >>~/.ssh/known_hosts

3
我并不想忽略这个警告,我已经收到了,将来还会继续收到。我需要一个脚本,在我收到警告后运行该脚本,它可以自动回答“是”的问题而无需人工交互。我没有办法手动输入“是”。我希望有一个"连接到此主机、回答是并且断开连接"的SSH参数,或者其他实现这个功能的方法。 - John O
你的命令有效,但我不确定它在做什么。谢谢。我还添加了Batchmode,这样当它到达密码提示时就会退出。非常感谢。 - John O
15
糟糕的想法。查看其他答案和评论以了解原因和更好的替代方案。简而言之:使用 StrictHostKeyChecking=accept-new 替代。 - cregox
2
@cregox 这不是一个糟糕的想法,只是你的阅读理解能力很差。这对我来说是几年前的事情了,但我没有办法交互式地使用系统。我无法手动更新密钥到新的密钥。在我的情况下,我已经通过电话和电子邮件与外部主机进行了验证,证实这只是他们那边不可避免的系统问题。我还能够编写一个脚本,可以作为替代品执行,而不是我坐在那里使用键盘确认我想要这个。它不是自动化的,我必须调用脚本。没有人提供替代方案。 - John O
1
使用过Docker。 - JRichardsz
显示剩余3条评论

53

由于您正在尝试通过在进行ssh连接的主机上运行bash脚本来自动化此过程,并且假设:

  • 您不想忽略主机密钥,因为那会增加额外的安全风险。
  • ssh到的主机上的主机密钥很少更改,如果确实更改,则有一个很好的、众所周知的原因,比如"目标主机被重建了"。
  • 您想运行此脚本一次将新密钥添加到known_hosts中,然后让known_hosts保持不变。

请在您的bash脚本中尝试以下内容:

# Remove old key
ssh-keygen -R $target_host

# Add the new key
ssh-keyscan $target_host >> ~/.ssh/known_hosts

6

您只需要更新从服务器发送的当前指纹即可。只需输入以下内容,您就可以开始使用:

ssh-keygen -f "/home/your_user_name/.ssh/known_hosts" -R "server_ip"

那就是这样 - Florida Man

4
只是添加了最“现代”的方法。 就像其他答案一样 - 这意味着你是盲目地接受来自主机的密钥。要小心使用!
HOST=hostname; ssh-keygen -R $HOST && ssh-keyscan -Ht ed25519 $HOST >> "$HOME/.ssh/known_hosts"

首先使用-R删除任何条目,然后生成一个哈希(-H)的known_hosts条目,我们将其追加到文件末尾。
此答案一样,更倾向于使用ed25519。

1

获取SSH主机IP地址(或DNS名称)列表,输出到文件 > ssh_hosts

运行一行命令在控制节点上填充~/.ssh/known_hosts文件(通常用于准备目标节点以进行Ansible运行)

注意:假设我们更喜欢ed25519类型的主机密钥

# add the target hosts key fingerprints
while read -r line; do ssh-keyscan -t ed25519 $line >> ~/.ssh/known_hosts; done<ssh_hosts

# add the SSH Key('s) public bit to target hosts `authorized_keys` file
while read -r line; do ssh-copy-id -i /path/to/key -f user@$line; done<ssh_hosts


0
ssh -o UserKnownHostsFile=/dev/null user@host

2
仅有代码的答案并不高质量。虽然该代码可能会有用,但您可以通过解释它为什么有效、如何工作、何时应使用以及其限制是什么来改进它。请编辑您的答案以包含说明和相关文档链接。 - Stephen Ostermiller
如果我能简单地回复一个“k”就好了。 - fa wildchild
从被接受的答案中,将ssh -o 'StrictHostKeyChecking no' ...这段代码翻译为中文会更好。如果不需要文件,为什么要打开空文件描述符呢? - Lockszmith

-5

添加以下文件

~/.ssh/config

并将其作为内容保存在文件中

StrictHostKeyChecking no

这个设置将确保ssh永远不会再次要求指纹检查。 这应该非常小心地添加,因为这将非常危险,并允许访问所有指纹。


6
私人互联网,MB。我同意。不要在真实的环境中这样做。 - TamusJRoyce
1
显然,这仅适用于您的互联网VPC/网络内部的私有网络主机。 公共面向的主机不应该有这个。 - vishal sahasrabuddhe
2
这是非常冒险的建议,因为它没有限定条件说明这是一个巨大的安全漏洞,而且指令会在全局范围内添加,而不是在Host块内添加。 - Chris Adams
1
@vishalsahasrabuddhe 这是一个重要的限定条件,原始评论中没有提到,但仍然很鲁莽,因为这将影响每个SSH连接,所以你在赌注上,希望没有人会改变使用模式或将该配置复制到其他地方。更安全的做法是建议使用 StrictHostKeyChecking accept-new 或使用 Host 仅为预期服务器降低安全性。 - Chris Adams
如果你的目标是嵌入式Linux系统,用户目录只读,并且嵌入式设备在每次重启时更改指纹,那么你几乎需要像这样的东西。我发现ssh-keygen -R解决方案可以达到效果,但会产生一些不必要的输出噪音。 - Scott Prive
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接