为什么通过SSH连接GitHub时会出现错误“警告:远程主机标识已更改”?

629

就在不久前,当我向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.

这是正常的吗?我该如何解决?


2
ssh-keygen -R github.com - 这个命令不会更新以前的 ssh 密钥(您的 ~/.ssh/id_rsa~/.ssh/id_rsa.pub 保持不变)。 - Constantin De La Roche
6
GitHub在三月份更改了他们的RSA密钥,并在多个地方宣布了这一消息。以下是描述此更改及其处理方法的网页链接: https://github.blog/2023-03-23-we-updated-our-rsa-ssh-host-key/ - Roman Czerwinski
我今天刚拿到这个 - undefined
7个回答

932
这是因为在2023年3月24日,GitHub 更新了用于保护GitHub.com Git操作的RSA SSH主机密钥,因为私钥曾短暂地暴露在公共GitHub存储库中。如果您在该日期之前在SSH客户端中记住了GitHub的先前密钥指纹,则会收到该消息。
根据链接的博客文章,解决方案是通过运行以下命令删除旧密钥:
$ ssh-keygen -R github.com

现在下一个 git 连接(拉取、推送或克隆)应该询问你是否信任新的 SSH 密钥。在输入 yes 之前,请使用列表确保显示的新密钥是有效的:

https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/githubs-ssh-key-fingerprints

请参考博客文章了解其他解决此问题的方法。


2
在Windows上使用Git Bash时,我发现上述命令可以工作,但在git push时,我收到了一条消息,说无法建立github.com的真实性。询问是否要继续,我输入了“yes”,现在一切都正常工作。 - AlainD
9
@AlainD:这是预期的,因为该命令基本上只是说“忘记旧的公钥”,下一次将信任新的公钥。如果您想正确处理它,最好提前保存新的、已知正确的公钥(博客文章告诉您如何操作)。 - Joachim Sauer
5
我有一个旧的RSA密钥用于ssh.github.com,还有一些隐藏在~/.ssh/known_hosts中的github.com密钥。如果你看到它,请将其删除;按照@AlainD描述的操作,在键入“Yes”后会进行更新。 - Jacob Crofts
1
@amr 当没有记录时,就会出现这样的提示信息。 - OrangeDog
我真希望他们在错误信息中包含这个命令。 - jonincanada
显示剩余8条评论

53
根据GitHub的博客文章,他们的SSH密钥已经泄漏,因此他们重新生成了密钥。
您需要运行以下命令来删除已存储的密钥:
ssh-keygen -R github.com

这应该输出类似于:

# Host github.com found: line 1
.ssh/known_hosts updated.

如果你想要主动一些,可以跟着一个命令来获取他们的新密钥。这在 Windows 上可能不起作用,并且没有必要。下次尝试访问 GitHub 时,系统会提示你保存新密钥。
curl -L https://api.github.com/meta | jq -r '.ssh_keys | .[]' | sed -e 's/^/github.com /' >> ~/.ssh/known_hosts

完成后,您可以重新运行您尝试的git命令。


不起作用...出现错误。$ curl -L https://api.github.com/meta | jq -r '.ssh_keys | .[]' | sed -e 's/^/github.com /' >> ~/.ssh/known_hosts bash: jq: 命令未找到 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- 0:00:07 --:--:-- 0 curl: (60) SSL 证书问题: 无法获取本地颁发者证书 更多详情请参阅:https://curl.haxx.se/docs/sslcerts.html - Kamlesh
curl 无法验证服务器的合法性,因此无法与其建立安全连接。要了解更多关于此情况以及如何修复它的信息,请访问上述网页。 - Kamlesh
@Kamlesh 可能缺少 jq 库,请尝试运行以下命令进行安装:brew install jq。你也需要先安装 brew(https://brew.sh/)。 - nikitahl

47

是的,GitHub已经更新了他们的RSA主机密钥,如他们的博客文章中所述。你可以按照那里的说明来更新你的密钥。

然而,一些人发现OpenSSH也保存了IP地址的主机密钥,通过CheckHostIP选项。在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枚举所有IP地址并将其全部删除,因此手动删除密钥是最佳选择。

然后,您可以按照博客文章中的说明自动更新密钥:

$ curl -L https://api.github.com/meta | jq -r '.ssh_keys | .[]' | \
  sed -e 's/^/github.com /' >> ~/.ssh/known_hosts

1
他们列出了他们的IP地址,可以枚举它们(超过14000个),但是列表不完整,所以你的回答是最好的。 - Jasen
任何关于我的回答下面的讨论的见解都会很有帮助。你可能有@Isikyus评论的答案。 - Gabriel Staples
1
在遵循 GitHub 博客文章的建议(由 Sators 在这里提供作为答案),并在终端推送时看到错误“警告:'github.com'的 ECDSA 主机密钥与 IP 地址的密钥不同”后,我解决了这个问题。我还在RStudio GUI中使用按钮推送时出现错误,但是这个答案解决了所有问题。 - Heidi Rodenhizer
1
谢谢!我一直在获取(fetch)时遇到错误 "Warning: the ECDSA host key for 'github.com' differs from the key for the IP address '140.82.121.4' Offending key for IP in /home/gabriele/.ssh/known_hosts:10 Are you sure you want to continue connecting (yes/no)? no",而我不明白为什么会出现这种情况。我开始手动逐行删除这些行,但我变得很疯狂。你很好地解释了问题,并且这个命令彻底解决了我的问题! - Gabriele Buondonno

37

来自GitHub的我们更新了RSA SSH主机密钥,您可以做什么

为了谨慎起见,于2023年3月24日UTC 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密钥并更新新密钥。


15

GitHub博客建议简单地:

ssh-keygen -R github.com

不幸的是,这并不容易,我一直遇到以下错误,显示 GitHub 服务器存储在我的 known_hosts 文件中,通过 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服务相关的数千个IP地址来清理它们...

我设计了一个Ruby脚本,通过GitHub元API搜索发布的GitHub IP地址。它有限制——跳过巨大的“actions”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://dev59.com/nddmpIgBRmDukGFEOBw4
#
# 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
}

1
@jasen - 当我记录脚本的输出时,它就会出现。它在这个块中:140.82.112.0 / 20 -- 从 140.82.112.1 开始,到 140.82.127.255 结束。 - Jeff Ward

15
Ubuntu 20.04 上,使用 GitHub 上的 Ed25519 密钥,即使运行了 ssh-keygen -R github.com 命令并按照 主要答案 的建议操作,每次运行 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命令。感谢@Guntram Blohm)。

mv ~/.ssh/known_hosts ~/.ssh/known_hosts.bak

...现在git push终于又可以正常工作了!我不介意每次使用SSH连接到特定服务器时都必须重新验证所有我的SSH目的地,因此有效地删除~/.ssh/known_hosts文件是可以接受的。反正我几乎只用SSH来推送到GitHub和GitLab。

注意:在那之后第一次运行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的公钥指纹:
  • SHA256:uNiVztksCsDhcc0u9e8BujQXVUpKZIDTMczCvj3tD2s(RSA)
  • SHA256:br9IjFspm1vxR3iA35FWE+4VTyz1hYVLIE2t1/CeyWQ(DSA - 已弃用)
  • SHA256:p2QAMXNIC1TJYWeIOttrVc98/R1BUFWu3/LiyKgUfQM(ECDSA)
  • SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU(Ed25519)

4
如果您没有使用ssh进行其他操作,那么这可能是一个解决方法,但如果您连接到其他服务器,则意味着对它们的密钥所做的任何更改都将不会被注意到。 (显然,您还有其他密钥,因为它们在您的“known_hosts”文件的第14和15行上。最好像@bk2204的答案中那样删除密钥,或者记下行号(在您的情况下为14),然后手动删除第14行。 - Guntram Blohm
9
HTTPS和SSH使用不同的私钥。 HTTPS私钥没有泄漏,只有SSH私钥泄漏了。 - JBYoshi
2
@JBYoshi,我看到你的评论有几个赞,所以你能详细解释一下这意味着什么以及它与此相关吗?我不明白你告诉我的是什么,或者你是否在暗示我应该做些不同的事情,但我想学更多。 - Gabriel Staples
3
Gabriel,JBYoshi正在回复Davislor,他暗示在检查指纹与要检查的密钥之间存在循环性。实际上,您正在通过HTTPS验证已通过验证的SSH密钥指纹,这些指纹未受泄漏影响。因此没有循环性问题。一切都好。 - Luca Citi
2
是的,他们回答了我的问题。曾经发生过一些违规行为,其中有人使用从攻击者控制的网站获取的密钥或校验和进行“验证”。 - Davislor
显示剩余10条评论

1
如果您的curl命令出现错误,请使用以下内容编辑您的~/.ssh/known_hosts文件中的github.com条目:
github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=

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