如何known_hosts
安全地将主机密钥添加到 SSH 文件?
我正在设置一台开发机器,并且我想(例如)防止在使用 SSHgit
克隆存储库时出现提示。github.com
我知道我可以使用StrictHostKeyChecking=no
(例如这个答案),但这并不安全。
到目前为止,我发现...
GitHub 在以下网址发布了其 SSH 密钥指纹:GitHub 的 SSH 密钥指纹
我可以使用它
ssh-keyscan
来获取主机密钥github.com
。
我该如何将这些事实结合起来?给定一个预填充的指纹列表,我如何验证输出是否ssh-keyscan
可以添加到known_hosts
文件中?
我想我要问的是以下问题:
如何获取返回的密钥的指纹ssh-keyscan
?
假设我已经中间人攻击用于 SSH,但我可以信任 GitHub HTTPS 页面(因为它具有有效的证书链)。
这意味着我获得了一些(可疑的)SSH 主机密钥(来自ssh-keyscan
)和一些(可信的)密钥指纹。我该如何验证两者?
相关:如何对输出的主机部分进行哈希处理ssh-keyscan
?或者我可以在中混合使用哈希/非哈希主机known_hosts
吗?
答案1
“安全地”将密钥添加到文件的最重要部分known_hosts
是从服务器管理员处获取密钥指纹。密钥指纹应如下所示:
2048 SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8 github.com (RSA)
对于 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)
2)从服务器管理员处获取密钥指纹的副本 - 在这种情况下,导航到包含 github.com 上信息的页面
- 前往 github.com
- 前往帮助页面(如果登录则位于右侧菜单上;否则位于主页底部)。
- 在里面入门部分转到使用 SSH 连接到 GitHub
- 去测试您的 SSH 连接
- 将该页面的 SHA256 指纹复制到文本编辑器中以供日后使用。
3)比较两个来源的密钥
通过在文本编辑器中将它们直接放在另一个上方,很容易看出是否有变化
2048 SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8 github.com (RSA) #key recovered from github website
2048 SHA256:nThbg6kXUpJ3Gl7E1InsaspRomtxdcArLviKaEsTGY8 github.com (RSA) #key recovered with keyscan
(请注意,第二个密钥已被篡改,但它看起来与原始密钥非常相似 - 如果发生这种情况,则您将受到严重攻击,应联系可信赖的安全专家。)
如果密钥不同,则中止该过程并联系安全专家
4)如果密钥比较正确,那么你应该安装已经下载的密钥
cat github-key-temp >> ~/.ssh/known_hosts
或者为系统上的所有用户安装(以 root 身份):
cat github-key-temp >> /etc/ssh/ssh_known_hosts
自动密钥安装
如果您需要在构建过程中添加密钥,那么您应该按照上述手动过程的步骤 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
你现在应该摆脱任何ssh
已StrictHostKeyChecking
禁用的命令。
答案2
您可以在 known_hosts 文件中混合散列/非散列条目。
因此,如果您想添加 github 密钥,您只需执行以下操作:
ssh-keyscan github.com >> ~/.ssh/known_hosts
如果希望对其进行哈希处理,请添加 -H
ssh-keyscan -H github.com >> ~/.ssh/known_hosts
注意:这容易受到 MITM 攻击,它仅回答问题的“相关”部分。
答案3
现在 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
或者如果你想使用 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
答案4
我编写了简单的脚本(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"