安全地将主机(例如 GitHub)添加到 SSH known_hosts 文件

Rog*_*mbe 45 ssh

如何known_hosts安全地将主机密钥添加到 SSH文件?

我正在设置一台开发机器,我想(例如)防止git在我github.com使用 SSH克隆存储库时进行提示。

我知道我可以使用StrictHostKeyChecking=no(例如这个答案),但这并不安全。

到目前为止,我发现...

  1. GitHub 在https://help.github.com/articles/github-s-ssh-key-fingerprints/上发布了他们的 SSH 密钥指纹

  2. 我可以ssh-keyscan用来获取github.com.

我如何结合这些事实?给定一个预先填充的指纹列表,我如何验证可以将 的输出ssh-keyscan添加到known_hosts文件中?


我想我在问以下问题:

如何获取由 返回的密钥的指纹ssh-keyscan

假设我已经通过了 SSH 的MITM认证,但是我可以信任 GitHub HTTPS 页面(因为它有一个有效的证书链)。

这意味着我有一些(可疑的)SSH 主机密钥(来自ssh-keyscan)和一些(受信任的)密钥指纹。我如何验证一个与另一个?


相关:如何散列输出的主机部分ssh-keyscan?或者我可以混合散列/未散列的主机known_hosts吗?

Mic*_*ael 39

“安全地”向known_hosts文件添加密钥的最重要部分是从服务器管理员那里获取密钥指纹。密钥指纹应如下所示:

2048 SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8 github.com (RSA)
Run Code Online (Sandbox Code Playgroud)

在 GitHub 的情况下,通常我们不能直接与管理员交谈。但是,他们将密钥放在他们的网页上,以便我们可以从那里恢复信息。

手动钥匙安装

1)从服务器获取密钥的副本并获取其指纹。注意:检查指纹之前执行此操作。

$ ssh-keyscan -t rsa github.com | tee github-key-temp | ssh-keygen -lf -
# github.com:22 SSH-2.0-babeld-f3847d63
2048 SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8 github.com (RSA)
Run Code Online (Sandbox Code Playgroud)

2)从服务器管理员那里获取密钥指纹的副本 - 在这种情况下导航到包含 github.com 信息的页面

  1. 去github.com
  2. 转到帮助页面(如果已登录,则在右侧的菜单中;否则在主页底部)。
  3. 入门部分转到使用 SSH 连接到 GitHub
  4. 转到测试您的 SSH 连接
  5. 将 SHA256 指纹从该页面复制到文本编辑器中以备后用。

3)比较来自两个来源的密钥

通过在文本编辑器中将它们直接放在另一个之上,很容易查看某些内容是否发生了变化

2048 SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8 github.com (RSA) #key recovered from github website
2048 SHA256:nThbg6kXUpJ3Gl7E1InsaspRomtxdcArLviKaEsTGY8 github.com (RSA) #key recovered with keyscan
Run Code Online (Sandbox Code Playgroud)

(请注意,第二个密钥已被操纵,但它看起来与原始密钥非常相似——如果发生这种情况,您将受到严重攻击,应联系值得信赖的安全专家。)

如果密钥不同,请中止该过程并与安全专家联系

4)如果密钥比较正确,那么你应该安装你已经下载的密钥

cat github-key-temp >> ~/.ssh/known_hosts
Run Code Online (Sandbox Code Playgroud)

或者为系统上的所有用户安装(以 root 用户身份):

cat github-key-temp >> /etc/ssh/ssh_known_hosts
Run Code Online (Sandbox Code Playgroud)

自动安装密钥

如果您需要在构建过程中添加密钥,则应按照上述手动过程的第 1-3 步操作。

完成后,检查github-key-temp文件的内容并编写脚本将这些内容添加到已知的主机文件中。

if ! grep github.com ~/.ssh/known_hosts > /dev/null
then
     echo "github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==" >> ~/.ssh/known_hosts
fi
Run Code Online (Sandbox Code Playgroud)

您现在应该删除所有sshStrictHostKeyChecking禁用的命令。

  • [`如果!ssh-keygen -F github.com; 然后`](/sf/answers/849593391/)? (2认同)

Wee*_*Wee 30

您可以在 known_hosts 文件中混合散列/未散列条目。

所以如果你想添加 github 密钥,你可以这样做:

ssh-keyscan github.com >> ~/.ssh/known_hosts

如果你想要它散列,添加 -H

ssh-keyscan -H github.com >> ~/.ssh/known_hosts

  • 这不能回答问题。使用 ssh-keyscan 会受到中间人攻击,这意味着您存储的密钥可能是属于试图闯入您系统的攻击者的密钥。请参阅我的答案以了解检查事物的方法。 (8认同)
  • 散列您的条目允许您隐藏有关您用于连接的主机的信息。在 https://security.stackexchange.com/questions/56268/ssh-benefits-of-using-hashed-known-hosts 检查接受的答案 (5认同)

gen*_*ood 9

现在,GitHub通过其元数据 API 端点提供了 SSH 密钥和指纹(截至 2022 年 1 月),您可以利用对 GitHub 所使用的 TLS 证书的信任api.github.com(因为它是由证书颁发机构 (CA)签署的,该证书位于您系统的受信任根证书存储)以安全地获取其 SSH 主机密钥。

如果你已经jq安装了,你可以用这一行来完成

curl --silent https://api.github.com/meta \
  | jq --raw-output '"github.com "+.ssh_keys[]' >> ~/.ssh/known_hosts
Run Code Online (Sandbox Code Playgroud)

或者如果你想使用Python

curl --silent https://api.github.com/meta | \
  python3 -c 'import json,sys;print(*["github.com " + x for x in json.load(sys.stdin)["ssh_keys"]], sep="\n")' \
  >> ~/.ssh/known_hosts
Run Code Online (Sandbox Code Playgroud)


Jak*_*uje 5

最简单的方法是使用 手动获取密钥ssh-keyscan,手动验证它们:

$ ssh-keyscan -t rsa github.com | ssh-keygen -lf -
# github.com:22 SSH-2.0-libssh-0.7.0
2048 SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8 github.com (RSA)
Run Code Online (Sandbox Code Playgroud)

并将它们添加到您的脚本中,然后该脚本将携带“权威”公钥。

  • 注意。*[引起对不正确答案的关注](https://meta.stackexchange.com/questions/329971/getting-attention-for-answers-that-have-aways-been-in Correct)* - *“两个最重要的答案实际上是不安全的”* (3认同)
  • 这个答案很危险,因为隐藏在“手动验证”中是一个艰难的过程。我在下面添加了一个答案,试图解释如何做到这一点并安全地使用结果。 (2认同)

小智 5

我编写了简单的脚本(add_to_known_hosts)来处理这个问题:

它不会在known_hosts 文件中创建重复的条目,并且会检查指纹是否与作为第二个参数提供的条目匹配。

#!/usr/bin/env bash
# The first argument should be hostname (or IP)
# The second argument should be the SSH fingerprint from the server admin.
# Example: add_to_known_hosts github.com SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8

host=$1
fingerprint=$2

ip=$(getent hosts $1 | awk '{ print $1 }')
echo $ip

keys=$(ssh-keyscan -t rsa $host $ip)

# Iterate over keys (host and ip)
while IFS= read -r key; do
    # Extract Host name (or IP)
    key_host=$(echo $key | awk '{ print $1 }')

    # Extracting fingerprint of key
    key_fingerprint=$(echo $key | ssh-keygen -lf - | awk '{ print $2 }')

    # Check that fingerprint matches one provided as second parameter
    if [[ $fingerprint != $key_fingerprint ]]; then
      echo "Fingerprint match failed: '$fingerprint' (expected) != '$key_fingerprint' (got)";
      exit 1;
    fi
    
    # Add key to known_hosts if it doesn't exist
    if ! grep $key_host ~/.ssh/known_hosts > /dev/null
    then
       echo "Adding fingerprint $key_fingerprint for $key_host to ~/.ssh/known_hosts"
       echo $key >> ~/.ssh/known_hosts
    fi
done <<< "$keys"
Run Code Online (Sandbox Code Playgroud)