将 www.github.com 添加到 known_hosts 文件的安全/正确方法是啥?
Posted
技术标签:
【中文标题】将 www.github.com 添加到 known_hosts 文件的安全/正确方法是啥?【英文标题】:What is the secure/correct way of adding www.github.com to the known_hosts file?将 www.github.com 添加到 known_hosts 文件的安全/正确方法是什么? 【发布时间】:2018-09-15 03:44:05 【问题描述】:我想通过 ssh 访问我的 github 存储库。当我第一次访问存储库时,系统会询问我是否要将 github ssh 服务器添加到我的 known_hosts
文件中,这可以正常工作。该请求还向我显示了该服务器的 RSA 密钥指纹,我可以手动验证它是否与 github here 提供的相同。
这些是 OpenSSH 6.8 及更高版本(base64 格式)中显示的 SHA256 哈希:
SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8 (RSA)
SHA256:br9IjFspm1vxR3iA35FWE+4VTyz1hYVLIE2t1/CeyWQ (DSA)
问题是我想通过添加公钥来阻止该请求
在我第一次访问我的 git 存储库之前到我的 known_hosts
文件。这可以通过使用ssh-keyscan -t rsa www.github.com
命令来完成,该命令将为我提供known_hosts
文件所需格式的公钥。但是人们反复提到,这不安全,容易受到中间人攻击。他们没有提到的是如何正确地做。
那么如何使用github页面上提供的RSA指纹安全获取ssh服务器的主机公钥呢?我或多或少在寻找ssh-keyscan
命令的选项,该选项可让我添加预期的 rsa 指纹,并在主机指纹与给定指纹不匹配时导致命令失败。
感谢您的宝贵时间!
【问题讨论】:
【参考方案1】:在这种情况下,我会不使用 ssh-keyscan。
相反,我会使用它并通过将其指纹与 GitHub 提供的指纹进行比较来仔细检查结果。
然后继续使用SSH GitHub test,检查我是否得到:
Hi username! You've successfully authenticated, but GitHub does not
provide shell access.
所以,as recommended here,对于手动过程:
ssh-keyscan github.com >> githubKey
生成指纹:
ssh-keygen -lf githubKey
与 GitHub 提供的对比一下
最后,将githubKey
的内容复制到您的~/.ssh/known_hosts
文件中。
您可以使用wercker/step-add-to-known_hosts
自动执行该过程(仍然包括指纹步骤检查):它是wercker step,但可以推断为它自己的独立脚本。
- add-to-known_hosts:
hostname: github.com
fingerprint: 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48
type: rsa
但这将缺乏对help.github.com/articles/github-s-ssh-key-fingerprints
的检查:见下文。
使用 nmap 并没有多大帮助,因为 explained here:
使用
nmap
获取 SSH 主机密钥指纹,然后将其与ssh-keyscan
所说的指纹进行比较:在这两种情况下,指纹都来自相同的地方。 它与任何其他自动化解决方案一样容易受到 MITM 的攻击。验证 SSH 公钥的唯一安全有效的方法是通过一些受信任的带外通道。 (或者设置某种密钥签名基础设施。)
在这里,help.github.com/articles/github-s-ssh-key-fingerprints
仍然是“受信任的带外通道”。
【讨论】:
好的,但是如何从SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8
指纹中获取我必须添加到我的known_hosts
文件中的行?添加类似gihub.com ssh-rsa SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8
的内容不起作用。这中间的步骤正是我所缺少的。
@Knitschi 我已经修改了我的答案并添加了缺失的步骤。【参考方案2】:
根据VonC的回答,下面的脚本可以自动验证并添加密钥。像这样使用它:
$ ./add-key.sh github.com nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8
它会告诉您它是否成功验证并保存了指纹。
有关使用信息,请使用./add-key.sh --help
脚本:
#!/usr/bin/env bash
# Settings
knownhosts="$HOME/.ssh/known_hosts"
if [ "x$1" == "x-h" ] || [ "x$1" == "x--help" ] || [ $#1 == 0 ]; then
echo "Usage: $0 <host> <fingerprint> [<port>]"
echo "Example: $0 github.com nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8"
echo "The default port is 22."
echo "The script will download the ssh keys from <host>, check if any match"
echo "the <fingerprint>, and add that one to $knownhosts."
exit 1
fi
# Argument handling
host=$1
fingerprint=$2
port=$(if [ -n "$3" ]; then echo "$3"; else echo 22; fi)
# Download the actual key (you cannot convert a fingerprint to the original key)
keys="$(ssh-keyscan -p $port $host |& grep -v ^\#)";
echo "$keys" | grep -v "^$host" # Show any errors
keys="$(echo "$keys" | grep "^$host")"; # Remove errors from the variable
if [ $#keys -lt 20 ]; then echo Error downloading keys; exit 2; fi
# Find which line contains the key matching this fingerprint
line=$(ssh-keygen -lf <(echo "$keys") | grep -n "$fingerprint" | cut -b 1-1)
if [ $#line -gt 0 ]; then # If there was a matching fingerprint (todo: shouldn't this be -ge or so?)
# Take that line
key=$(head -$line <(echo "$keys") | tail -1)
# Check if the key part (column 3) of that line is already in $knownhosts
if [ -n "$(grep "$(echo "$key" | awk 'print $3')" $knownhosts)" ]; then
echo "Key already in $knownhosts."
exit 3
else
# Add it to known hosts
echo "$key" >> $knownhosts
# And tell the user what kind of key they just added
keytype=$(echo "$key" | awk 'print $2')
echo Fingerprint verified and $keytype key added to $knownhosts
fi
else # If there was no matching fingerprint
echo MITM? These are the received fingerprints:
ssh-keygen -lf <(echo "$keys")
echo Generated from these received keys:
echo "$keys"
exit 1
fi
【讨论】:
我的回答很好。 +1 如果它还检查它是否已经存在,那就太棒了,这样它就可以在 CI 设置中运行(例如,在每次提交时),而不是无休止地附加到 known_hosts 文件。 @ChrisTrahey 好主意!已实施。 这很好,直到ssh-keyscan -p $port $host 2> /dev/null
失败并且没有告诉你原因。我认为使用ssh-keyscan github.com 2>&1 | grep -v '#'
会更好。
@NorseGaud 不完全是,而且您的建议不起作用。首先,脚本当前会告诉您下载失败,您可以从那里进行调试,但我同意显示错误更好。使用2>&1
的提议只是捕获了stderr(并且可以更简单地写成command |& grep
),所以当放入一个变量时(就像脚本一样),抑制stderr 的问题仍然存在。必须以某种方式将 stdout 和 stderr 分开。我已经编辑了脚本来做到这一点。【参考方案3】:
我的单行允许错误报告失败:
touch ~/.ssh/known_hosts && if [ $(grep -c 'github.com ssh-rsa' ~/.ssh/known_hosts) -lt 1 ]; then KEYS=$(KEYS=$(ssh-keyscan github.com 2>&1 | grep -v '#'); ssh-keygen -lf <(echo $KEYS) || echo $KEYS); if [[ $KEYS =~ '(RSA)' ]]; then if [ $(curl -s https://help.github.com/en/github/authenticating-to-github/githubs-ssh-key-fingerprints | grep -c $(echo $KEYS | awk 'print $2')) -gt 0 ]; then echo '[GitHub key successfully verified]' && ssh-keyscan github.com 1>~/.ssh/known_hosts; fi; else echo \"ssh-keygen -lf failed:\\n$KEYS\"; exit 1; fi; unset KEYS; fi
【讨论】:
请注意,这仅适用于github.com
,并不是基于指纹安全添加密钥的通用解决方案。我也不确定为什么它必须是一个巨大的、难以理解的行......
@Luc One liner 允许您将其放入 CI 脚本中,而不会使它们膨胀。
我不想审核你的 CI 设置:P以上是关于将 www.github.com 添加到 known_hosts 文件的安全/正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
CentOS执行ping命令报错 name or service not know
HDR10 vs Dolby Vision: Here’s what you need to know about the HDR format war