将 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&gt; /dev/null 失败并且没有告诉你原因。我认为使用ssh-keyscan github.com 2&gt;&amp;1 | grep -v '#' 会更好。 @NorseGaud 不完全是,而且您的建议不起作用。首先,脚本当前会告诉您下载失败,您可以从那里进行调试,但我同意显示错误更好。使用2&gt;&amp;1 的提议只是捕获了stderr(并且可以更简单地写成command |&amp; 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 文件的安全/正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

个人-GIT使用方法

无法访问 Github

CentOS执行ping命令报错 name or service not know

mac 浏览器打不开github

HDR10 vs Dolby Vision: Here’s what you need to know about the HDR format war

CentOS ping www.baidu.com 报错 name or service not know