客户端提供了 SHA256 ssh 指纹,但服务器只知道 md5 指纹

客户端提供了 SHA256 ssh 指纹,但服务器只知道 md5 指纹

当连接到新的/未知的服务器(使用最新的 OpenSSH)时,例如:

ssh example.com

您将获得如下的指纹:

The authenticity of host 'example.org (192.0.2.42)' can't be established.
RSA key fingerprint is SHA256:7KMZvJiITZ+HbOyqjNPV5AeC5As2GSZES5baxy1NIe4.
Are you sure you want to continue connecting (yes/no)?

然而,服务器的指纹通常是以这种形式给出的:

f6:fc:1c:03:17:5f:67:4f:1f:0b:50:5a:9f:f9:30:e5

我如何检查真实性(无需麻烦服务器管理员提供 SHA256 指纹)?

答案1

以前指纹是以十六进制 md5 哈希值给出的。首先OpenSSH 6.8指纹现在显示为 base64 SHA256(默认)。您无法直接比较它们。

他们还添加了一个新的配置选项FingerprintHash。您可以把

FingerprintHash md5

在你的~/.ssh/config恢复到旧的(不太安全)默认或仅使用此选项供单独使用:

ssh -o FingerprintHash=md5 example.org

这将使指纹

MD5:f6:fc:1c:03:17:5f:67:4f:1f:0b:50:5a:9f:f9:30:e5

希望服务器管理员在不久的将来提供两种类型的指纹。

编辑:

正如Arch Linux 论坛,还有第三种选择:

Host example.org
    FingerprintHash md5

编辑:

您可以生成任意密钥的哈希值,如OpenSSH 手册

检索密钥:

  • 下载密钥ssh-keyscan example.org > key.pub
  • 或者:在服务器上找到密钥/etc/ssh

生成哈希:

  • 确保只有一行/类型,因此请删除所有其他行key.pub或运行ssh-keyscan -t rsa example.org > key.pub
  • ssh-keygen -l -f key.pub(默认哈希,取决于 OpenSSH 版本)
  • ssh-keygen -l -f key.pub -E md5(当前 OpenSSH 上的 md5)
  • awk '{print $2}' ssh_host_rsa_key.pub | base64 -d | sha256sum -b | awk '{print $1}' | xxd -r -p | base64(旧版 OpenSSH 上为 sha256)
  • (您可能需要以 ssh-keyscan 的较新版本开始该行,awk '{print $3}'因为格式已更改)

答案2

刚刚创建了一个小型 bash 脚本,它将打印出服务器上允许的所有密钥密码的指纹表(根据/etc/ssh/sshd_configSSH-256以及MD5算法。以下是示例输出:

❯ ssh-fingerprints
 +---------+------------------------------------------------------+
 | Cipher  | Algo and Fingerprint                                 |
 +---------+------------------------------------------------------+
 | RSA     | MD5:65:cc:63:49:ac:d6:a6:a8:5c:ab:58:12:f6:84:a4:75  |
 | RSA     | SHA-256:jlDPKCCRr1TkufVsZJf02ejXNQ7RB/vg09uGwKeSwnU  |
 +---------+------------------------------------------------------+
 | ECDSA   | MD5:fc:fa:b1:4a:6a:4f:4e:15:24:a0:28:14:d8:13:f2:58  |
 | ECDSA   | SHA-256:XqtbaJcdqem6s/R+T9NpXA7QKCTyPfzxC3f+2O/vfmY  |
 +---------+------------------------------------------------------+
 | ED25519 | MD5:03:1e:8e:0e:a8:4a:08:7a:49:35:af:2f:99:b8:9c:5b  |
 | ED25519 | SHA-256:HV5r6SFytqauiUrWcXd3zDGMzCYHj6RR6tKj0S0UhFI  |
 +---------+------------------------------------------------------+

 +---[RSA 3072]----+ +---[RSA 3072]----+ +---[ECDSA 256]---+ +---[ECDSA 256]---+ +--[ED25519 256]--+ +--[ED25519 256]--+
 |         ..      | |....     .   .o. | |o+E.  ... .      | |      . . .      | |                 | |     .Eo+.+      |
 |         +..     | |.....   . o + .o.| |o=o. .   o       | |       o =   o   | |                 | |    . .  * * o   |
 |  o E    oO      | |..oo ..o o + oo.o| |o o..     .      | |        . = + .  | |    o o          | |     .  + + O +  |
 | + o    o+o.     | | o..o.=+. .. .++o| | .     .   .     | |           + =   | | . . * o         | |       = + * = o |
 |. + .  oSo       | |.. .o .+S ..E.+oo| |        S .      | |        S . = + o| |o o . + S        | |    . + S O * +  |
 | . +  o .        | |.    o.+ . o.+ oo| |         o       | |       . o * +.Bo| |=. + .   .       | |   . o = B * o   |
 |  ..oo .         | |      . + o . ..o| |        + o      | |        = B . +++| |+.o.Eo           | |  o . .   o .    |
 |   +o .          | |         . .   . | |      .* . o     | |       o.*  ...+E| |oo.o+.           | | o   . . o       |
 |  . ..           | |                 | |     ...=oo      | |        *B+. .o*%| |. =o ..          | |  ... ooo        |
 +------[MD5]------+ +----[SHA256]-----+ +------[MD5]------+ +----[SHA256]-----+ +------[MD5]------+ +----[SHA256]-----+

脚本也将在SSH以下版本的服务器上运行6.8-E md5添加选项之前)。

编辑:更新了 SSH 的最新版本,现在通过 ASCII 图像支持切换默认密码。

编辑:将算法和指纹合并到一列,以便更轻松地复制和粘贴最近的 SSH 客户端中可用的验证。

您可以从以下位置获取此脚本的最新版本:https://github.com/kepi/ssh-fingerprints

#! /bin/bash
#
# ssh-fingerprints
#
# Source: https://github.com/kepi/ssh-fingerprints
#
# MIT License
# Copyright 2018 Ondra Kudlík (Kepi) <[email protected]>
#
set -eu

# standard sshd config path
readonly SSHD_CONFIG=/etc/ssh/sshd_config

readonly LINE=" +---------+------------------------------------------------------+"


# Warning: don't use in a pipe, because a pipe runs in a
# subshell and thus would throw away changes to global variables
function parse_fp {
    local algo=$1 n=0 filter line

    if [ "${2:-}" = old ] ; then
        # Older OpenSSH versions don't include the hash algorithm prefix
        filter="s/^\\([^ =]*\\).*/\\1/"
    else
        # Newer OpenSSH versions do include the hash algorithm prefix; remove
        filter="s/^${algo^^}:\\([^ =]*\\).*/\\1/"
    fi

    while read -r line
    do
        n=$((n + 1))
        if [[ $n -eq 1 ]] ; then
            ALGOS[$algo]=$(echo "$line" | sed "$filter")
        else
            # Alter old versions' ASCII art box to include algorithm
            if [ "$line" = "+-----------------+" ] ; then
                case $algo in
                    md5)    line="+------[MD5]------+" ;;
                    sha256) line="+----[SHA256]-----+" ;;
                esac
            fi

            ASCII[$n]="${ASCII[$n]:-} ${line}"
        fi
    done
}        


# *** MAINLINE ***
# header
echo "$LINE"
printf " | %-7s | %-52s |\n" "Cipher" "Algo and Fingerprint"
echo "$LINE"

declare -A ALGOS
declare -a ASCII

# fingerprints
hostkey_files=$(awk '/^HostKey/ { print $2 ".pub" }' $SSHD_CONFIG)
if [ -z "$hostkey_files" ] ; then
    # If HostKey not set in $SSHD_CONFIG, use the default
    hostkey_files='/etc/ssh/ssh_host_rsa_key.pub
                   /etc/ssh/ssh_host_ecdsa_key.pub
                   /etc/ssh/ssh_host_ed25519_key.pub'
fi
# (Fake piping into while loop by using a redirect, because a pipe runs in a
# subshell and thus would throw away changes to global variables)
while read -r host_key
do
    cipher=$(echo "$host_key" |
               sed -r 's/^.*ssh_host_([^_]+)_key\.pub$/\1/' |
               tr '[:lower:]' '[:upper:]')
    if [ "$cipher" = DSA ] ; then
        continue
    fi

    if [[ -f "$host_key" ]] ; then
        if ssh-keygen -E md5 -l -f "$host_key" &>/dev/null
        then
            for algo in md5 sha256 ; do
                parse_fp $algo < <(ssh-keygen -E $algo -lv -f "$host_key" |
                                       sed '/^[0-9]/ s/^[^ ]* \([^ ]*\).*/\1/')
            done
        else
            parse_fp md5 old < <(ssh-keygen -lv -f "$host_key" |
                                     sed '/^[0-9]/ s/^[^ ]* \([^ ]*\).*/\1/')
            # Note: no ASCII art
            # TO-DO: Use https://github.com/atoponce/keyart Python script
            parse_fp sha256 old < <(cut -f2 -d' ' "$host_key" |
                                        base64 -d |
                                        openssl dgst -sha256 -binary |
                                        base64)
        fi

        printf " | %-7s | %-52s |\n" "$cipher" "MD5:${ALGOS[md5]}"
        printf " | %-7s | %-52s |\n" "$cipher" "SHA256:${ALGOS[sha256]}"
        echo "$LINE"
    fi
done < <(echo "$hostkey_files")

echo
for line in "${ASCII[@]}"; do
    echo "$line"
done

这只是使用JonnyJD答案中的信息进行的漂亮打印。谢谢。

答案3

事实证明,ssh-keygen(版本 6.6 之后;大概是 6.8)有一个-E md5选项,它会将指纹打印为 md5 指纹。因此,如果您可以独立获取服务器的公钥文件,则可以将其提供给服务器ssh-keygen -E md5 -l -f ssh_host_rsa_key.pub并获取您熟悉的指纹。

答案4

我喜欢 Kepi 的想法,但不幸的是它对我来说不再起作用了,所以我查看了脚本并使其发挥作用,同时我还简化了它并删除了 ASCII 艺术,因为我不需要它。

要直接运行我的脚本,请运行:

curl -sS https://raw.githubusercontent.com/caballerofelipe/scripts/master/ssh/ssh_fingerprint.sh | bash

这是我的脚本(将来可能会改变GitHub):

#!/bin/bash

# To run this file directly from a computer without downloading run this:
# curl -sS https://raw.githubusercontent.com/caballerofelipe/scripts/master/ssh/ssh_fingerprint.sh | bash

# Used to show SSH fingerprints
# Inspired by this post: http://superuser.com/a/1030779/369045

# standard sshd config path
SSH_DIR=/etc/ssh/

# Helper functions
function tablize {
    printf "| %-7s | %-7s | %-47s |\n" $1 $2 $3
}
LINE="+---------+---------+-------------------------------------------------+"

# Header
echo $LINE
tablize "Cipher" "Algo" "Fingerprint"
echo $LINE

# Fingerprints
for i in $(ls $SSH_DIR/*.pub); do
    md5_result=$(ssh-keygen -l -f $i -E md5)
    sha256_result=$(ssh-keygen -l -f $i -E sha256)
    cipher=$(echo $md5_result | sed 's/.*(//' | sed 's/)[^)]*//')
    md5=$(echo $md5_result | awk '{print $2}' | sed 's/^[^:]*://g')
    sha256=$(echo $sha256_result | awk '{print $2}' | sed 's/^[^:]*://g')
    tablize $cipher MD5 $md5
    tablize $cipher SHA-256 $sha256
    echo $LINE
done

相关内容