为什么通过SSH连接到GitHub会出现错误"Warning: Remote Host Identification Has Changed"?

回答 6 浏览 4.7万 2023-03-24

就在不久前,我在推送到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.

这是否正常,我应该如何解决?

Dheeraj Vepakomma 提问于2023-03-24
ssh-keygen -R github.com - 这个命令并不更新以前的ssh密钥(你的~/.ssh/id_rsa & ~/.ssh/id_rsa.pub将保持不变)。Constantin De La Roche 2023-03-27
6 个回答
#1楼 已采纳
得票数 739

发生这种情况是因为在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

请参考博客文章,以了解修复该问题的其他方法。

Dheeraj Vepakomma 提问于2023-03-24
user3840170 修改于2023-03-25
此外,GitHubs SSH密钥的指纹可以在这里找到:docs.github.com/en/authentication/…Sever van Snugg 2023-03-24
在Windows上使用Git Bash,我发现上面的命令起作用了,但在git push上我得到一个信息,说"authenticity of github.com can't be establish"。问我是否要继续,我输入了"是",现在一切又正常了。AlainD 2023-03-24
@AlainD:那是例外,因为这个命令基本上只是说"忘记旧的公钥",新的公钥将在下次被信任。如果你想正确对待它,最好提前保存新的、已知正确的公钥(博文中告诉你如何做)。Joachim Sauer 2023-03-24
我有一个ssh.github.com的旧RSA密钥,此外还有github.com的密钥藏在~/.ssh/known_hosts。如果你看到它,请将其删除;在你输入"yes"后,它将被更新,正如@AlainD所描述的。Jacob Crofts 2023-03-24
@amr这就是没有记录的时候的信息。OrangeDog 2023-03-27
#2楼
得票数 35

来自Github的信息:

At approximately 05:00 UTC on March 24 [2023], out of an abundance of caution, we replaced our RSA SSH host key used to secure Git operations for GitHub.com. We did this to protect our users from any chance of an adversary impersonating GitHub or eavesdropping on their Git operations over SSH. This key does not grant access to GitHub’s infrastructure or customer data. This change only impacts Git operations over SSH using RSA. Web traffic to GitHub.com and HTTPS Git operations are not affected.

解决方法:从.ssh/known_hosts中删除github的旧RSA SSH密钥,并更新新的密钥。 https://github.blog/2023-03-23-we-updated-our-rsa-ssh-host-key/#what-you-can-do

Dishant Walia 提问于2023-03-24
Brian61354270 修改于2023-03-24
#3楼
得票数 33

根据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命令。

Sators 提问于2023-03-24
不工作....给出了错误。$ curl -L api.github.com/meta | jq -r '.ssh_keys | .[]' | sed -e 's/^/github.com /' > > ~/.ssh/known_hosts bash: jq: command not found % Total % Received % Xferd Average Speed Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 --:-:-- 0:00:07 --:-- 0 curl: (60) SSL certificate problem: unable to get local issuer certificate More details here:curl.haxx.se/docs/sslcerts.htmlKamlesh 2023-03-26
curl未能验证该服务器的合法性,因此无法与之建立安全连接。要了解更多关于这种情况以及如何修复它,请访问上述网页。Kamlesh 2023-03-26
@Kamlesh 你那边可能缺少jq库,试着运行这个来安装它:brew install jq.你还需要安装一个brew(brew.sh)。nikitahl 2023-03-27
#4楼
得票数 33

是的,正如他们的博文中提到的,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地址,我们不可能列举出所有的IP地址并用ssh-keygen把它们全部删除,所以手动删除密钥本身是最好的选择。

然后,你可以按照博文中的指示自动更新钥匙:

$ curl -L https://api.github.com/meta | jq -r '.ssh_keys | .[]' | \
  sed -e 's/^/github.com /' >> ~/.ssh/known_hosts
bk2204 提问于2023-03-24
bk2204 修改于2023-03-29
他们列出了他们的ip地址,而且有可能列举出来(有超过14000个),然而这个名单是不称职的,所以你的答案是最好的。Jasen 2023-03-29
我的答案下的讨论的任何见解都会有帮助。你可能有@Isikyus '的评论的答案。Gabriel Staples 2023-03-29
#5楼
得票数 12

在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的答案,而不是运行下面的mvcmd。谢谢,@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的公钥指纹:

  • SHA256:uNiVztksCsDhcc0u9e8BujQXVUpKZIDTMczCvj3tD2s(RSA)
  • SHA256:br9IjFspm1vxR3iA35FWE+4VTyz1hYVLIE2t1/CeyWQ (DSA - 废弃的)
  • SHA256:p2QAMXNIC1TJYWeIOttrVc98/R1BUFWu3/LiyKgUfQM(ECDSA)
  • SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU (19)
Gabriel Staples 提问于2023-03-24
Gabriel Staples 修改于2023-03-24
如果你不使用ssh做其他事情,这可能是一个变通办法,但如果你有其他的服务器要连接,这意味着对它们的密钥的任何改变都不会被注意。(显然你还有一些其他的,因为钥匙在你的known_hosts的第14和15行。最好像@bk2204'的回答那样删除密钥,或者记下行号(你的情况是14),然后手动删除14行。Guntram Blohm 2023-03-24
HTTPS和SSH使用不同的私钥。HTTPS的私钥没有被泄露,只有SSH的私钥。JBYoshi 2023-03-24
@JBYoshi,我看到你的评论有好几处加分,那么你能不能多解释一下这意味着什么,以及它是如何相关的?我不明白你在告诉我什么,或者你是否表示我应该做一些不同的事情,但想了解更多。Gabriel Staples 2023-03-25
Gabriel,JBYoshi是在回答Davislor,他暗示用你试图检查的钥匙来检查指纹存在循环性。实际上,你是用通过HTTPS验证的指纹来验证SSH密钥,而HTTPS并没有受到泄漏的影响。所以没有循环性。一切都很好。Luca Citi 2023-03-26
是的,他们回答了我的问题。有一些漏洞,有人用密钥或校验和 "验证",他们从攻击者控制的网站获得。Davislor 2023-03-26
#6楼
得票数 8

github博客的建议很简单:

ssh-keygen -R github.com

不幸的是,这并不容易,我一直得到如下的错误,显示github服务器在我按IP地址存储的know_hosts中。

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

你必须搜索1000个与github.com的服务相关的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
}
Jeff Ward 提问于2023-03-27
@jasen - 当我记录脚本的输出时,它确实如此。它就在这个区块中:140.82.112.0 / 20 -- 始于140.82.112.1,止于140.82.127.255Jeff Ward 2023-03-30