就在不久前,我在推送到 GitHub 时开始收到此警告。
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 a host key has just been changed.
这是否正常,我该如何解决?
发生这种情况是因为在 2023 年 3 月 24 日,GitHub 更新了他们的 RSA SSH 主机密钥 用于保护 GitHub.com 的 Git 操作,因为私钥曾短暂暴露在公共 GitHub 存储库中。如果您在该日期之前记得 GitHub 在 SSH 客户端中的先前密钥指纹,您将收到该消息。
根据链接的博客文章,解决方案是通过运行此命令删除旧密钥:
$ ssh-keygen -R github.com
现在下一个
git
连接(拉、推或克隆)应该询问您是否信任新的 SSH 密钥。在输入yes
之前,使用列表确保显示的新密钥有效:
请参阅博文了解其他解决问题的方法。
来自 Github:
在 2023 年 3 月 24 日世界标准时间 05:00 左右,出于谨慎考虑,我们更换了用于保护 GitHub.com 的 Git 操作的 RSA SSH 主机密钥。我们这样做是为了保护我们的用户免受对手冒充 GitHub 或通过 SSH 窃听他们的 Git 操作的任何机会。此密钥不授予对 GitHub 基础设施或客户数据的访问权限。此更改仅影响使用 RSA 通过 SSH 的 Git 操作。 GitHub.com 的 Web 流量和 HTTPS Git 操作不受影响。
解决方案:从 .ssh/known_hosts 中删除 github 的旧 RSA SSH 密钥并更新新密钥。 https://github.blog/2023-03-23-we-updated-our-rsa-ssh-host-key/#what-you-can-do
根据 Github 的博客文章,他们的 SSH 密钥被泄露,因此他们重新生成了他们的密钥。
您需要通过运行删除存储的密钥:
$ ssh-keygen -R github.com
应该输出如下内容:
# Host github.com found: line 1
.ssh/known_hosts updated.
随后是获取新密钥的命令:
$ curl -L https://api.github.com/meta | jq -r '.ssh_keys | .[]' | sed -e 's/^/github.com /' >> ~/.ssh/known_hosts
完成后,您可以重新运行您尝试的
git
命令。
是的,GitHub 更新了他们的 RSA 主机密钥,如 他们的博客文章 中所述。您可以按照那里的说明更新您的密钥。
然而,有些人发现OpenSSH还通过
CheckHostIP
选项保存了IP地址的主机密钥。这是在 OpenSSH 8.5 之前默认启用的,但往往没有帮助,因为它使旋转变得困难,因此在该版本中被禁用。也就是说,它可以像这样解决(在 Linux 和 Git Bash 上):
$ sed -i -e '/AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31\/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi\/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==/d' ~/.ssh/known_hosts
在 macOS 上也是如此:
$ sed -i '' -e '/AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31\/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi\/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==/d' ~/.ssh/known_hosts
无论是主机名还是 IP 地址,它都会删除找到的密钥。由于 GitHub 使用多个 IP 地址,实际上不可能枚举所有地址并用
ssh-keygen
将它们全部删除,因此手动删除密钥本身是最好的选择。
然后您可以按照博客文章中的说明自动更新密钥:
$ curl -L https://api.github.com/meta | jq -r '.ssh_keys | .[]' | \
sed -e 's/^/github.com /' >> ~/.ssh/known_hosts
在 Ubuntu 20.04 上,使用 Github 上的 ed25519 密钥,即使在运行
ssh-keygen -R github.com
之后,根据 main answer,我每次运行时都会看到这些通知 git push
:
$ git push
Warning: the ECDSA host key for 'github.com' differs from the key for the IP address '140.82.112.4'
Offending key for IP in /home/gabriel/.ssh/known_hosts:14
Matching host key in /home/gabriel/.ssh/known_hosts:15
Are you sure you want to continue connecting (yes/no)? yes
Warning: the ECDSA host key for 'github.com' differs from the key for the IP address '140.82.112.4'
Offending key for IP in /home/gabriel/.ssh/known_hosts:14
Matching host key in /home/gabriel/.ssh/known_hosts:15
Are you sure you want to continue connecting (yes/no)? yes
Warning: the ECDSA host key for 'github.com' differs from the key for the IP address '140.82.112.4'
Offending key for IP in /home/gabriel/.ssh/known_hosts:14
Matching host key in /home/gabriel/.ssh/known_hosts:15
Are you sure you want to continue connecting (yes/no)? yes
所以,我终于删除了我的
~/.ssh/known_hosts
文件,重命名如下:
(更新:尝试 @bk2204 的回答 而不是运行下面的
mv
cmd。谢谢,@Guntram Blohm)。
mv ~/.ssh/known_hosts ~/.ssh/known_hosts.bak
...现在
git push
终于可以正常工作了!我不在乎每当我再次使用 ssh 到特定服务器时我必须重新验证我的所有 ssh 目的地,所以有效地删除 ~/.ssh/known_hosts
文件就可以了。除了推送到 GitHub 和 GitLab 之外,我几乎不使用 ssh。
注意:我第一次跑
git push
之后就得输入yes
,如下图:
$ git push
The authenticity of host 'github.com (140.82.112.4)' can't be established.
ECDSA key fingerprint is SHA256:p2QAMXNIC1TJYWeIOttrVc98/R1BUFWu3/LiyKgUfQM.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'github.com,140.82.112.4' (ECDSA) to the list of known hosts.
Everything up-to-date
但是,在输入
yes
之前,我首先在 GitHub 的网站上验证了 SHA256:p2QAMXNIC1TJYWeIOttrVc98/R1BUFWu3/LiyKgUfQM
指纹是正确的,并且来自 GitHub。 GitHub 在这里有每种密钥类型的指纹:https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/githubs-ssh-key-fingerprints
这些是 GitHub 的公钥指纹:
(RSA)SHA256:uNiVztksCsDhcc0u9e8BujQXVUpKZIDTMczCvj3tD2s
(DSA - 已弃用)SHA256:br9IjFspm1vxR3iA35FWE+4VTyz1hYVLIE2t1/CeyWQ
(ECDSA)SHA256:p2QAMXNIC1TJYWeIOttrVc98/R1BUFWu3/LiyKgUfQM
(Ed25519)SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU
github 博客 简单地建议:
ssh-keygen -R github.com
不幸的是,这并不容易,我不断收到如下错误,表明 github 服务器在我的已知主机中,按 IP 地址存储。
Warning: the ECDSA host key for 'github.com' differs from the key for the IP address '192.30.255.113'
Offending key for IP in /.ssh/known_hosts:19
Matching host key in /.ssh/known_hosts:178
Are you sure you want to continue connecting (yes/no)? yes
你必须搜索与 github.com 的服务关联的 1000 个 IP 地址才能清理它们......😈
我设计了一个 Ruby 脚本来搜索通过 GitHub 元 API 发布的 github IP 地址。它是有限的——它跳过了巨大的“动作”IP 范围,并且只适用于 IPv4,但希望它能帮助其他人不必按
yes
很多次。
https://gist.github.com/jcward/5a64c17a6b61de0f7a4d85d004e7679e
出于存档目的转载于此:
#!/usr/bin/env ruby
#
# https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/githubs-ssh-key-fingerprints
# https://stackoverflow.com/questions/75830783
#
# Scan for github IP addresses in your knwon_hosts and remove them
# - Takes ~1.5 minutes on my machine
# - Skips the huge "actions" IP ranges
# - Skips IPv6
require 'json'
meta = JSON.parse `curl -s https://api.github.com/meta`
def num_to_ipv4 v
(v >> 24 & 255).to_i.to_s + "." +
(v >> 16 & 255).to_i.to_s + "." +
(v >> 8 & 255).to_i.to_s + "." +
(v >> 0 & 255).to_i.to_s
end
def get_ips_for octals, bits
ips = []
base = (octals[0] << 24) | (octals[1] << 16) | (octals[2] << 8) | octals[3]
num = 2**(32-bits)
0.upto(num) { |add|
ips.push( num_to_ipv4( base + add ) )
}
return ips
end
meta.each { |key, value|
next if key=="actions" # These ranges are too large
if (value.is_a?(Array)) then
value.each { |ip|
if (ip.match(/(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)/)) then
octals = [$1, $2, $3, $4].map(&:to_i)
bits = $5.to_i
ips = get_ips_for(octals, bits)
puts "# Scanning #{ key } range -- #{ ips.length } IPs"
ips.each { |ip|
search = `ssh-keygen -H -F #{ ip }`
if (search.length > 10) then
puts "Running: ssh-keygen -R #{ ip }"
`ssh-keygen -R #{ ip }`
end
}
end
}
end
}