获取 SSH 服务器密钥指纹

loo*_*bee 119 ssh

有没有办法以编程方式获取 SSH 服务器密钥指纹而不对其进行身份验证

我正在尝试ssh -v user@host false 2>&1 | grep "Server host key",但如果未设置基于密钥的身份验证,则会挂起等待密码。

And*_*ese 100

您可以通过组合ssh-keyscan和来做到这一点ssh-keygen

$ file=$(mktemp)
$ ssh-keyscan host > $file 2> /dev/null
$ ssh-keygen -l -f $file
521 de:ad:be:ef:de:ad:be:ef:de:ad:be:ef:de:ad:be:ef host (ECDSA)
4096 8b:ad:f0:0d:8b:ad:f0:0d:8b:ad:f0:0d:8b:ad:f0:0d host (RSA)
$ rm $file
Run Code Online (Sandbox Code Playgroud)

(不幸的是,更简单的方法ssh-keyscan host | ssh-keygen -l -f /dev/stdin不起作用)

  • OpenSSH >= 7.2 ssh-keyscan 能够从标准输入读取:`​​ssh-keyscan host | ssh-keygen -lf -` (48认同)
  • `ssh-keygen -l -f -` 在 ssh-keygen 7.2 及更高版本中确实可以正常工作。它会为 STDERR 生成一些可以过滤掉的注释行,如 Anthony Geoghegan 或 `ssh-keyscan host 2>/dev/null | 的回答中所述。ssh-keygen -l -f -` (7认同)
  • 不过,也许`ssh-keygen -l -f - <(ssh-keyscan host)` 可以? (4认同)
  • 新版本的 openssh(至少 7.2)将指纹显示为 SHA256(例如:`2048 SHA256:gYz11pP/v/SMzUD58jrZ+m1EFC1pvyMxvIrg4PYlvDY`)如果你想要旧格式,提供`-E md5`看到类似`2048 MD5:0b:f5:49:d2:69:a5:49:2c:d9:45:75:87:4d:a0:7d:33`的内容。 (4认同)
  • 只需这样做:`ssh-keygen -l -f <(ssh-keyscan host)` (3认同)
  • 对于 shell 脚本来说,这是一个相当糟糕的表达式,因为它依赖于支持它的 shell,而 POSIX shell 则不然。 (2认同)

Ant*_*gan 88

我最近不得不自己做这件事,所以我想我会添加一个答案,显示如何使用进程替换在一行中完成(使用OpenSSH 7.2 或更高版本):

ssh-keygen -lf <(ssh-keyscan hostname 2>/dev/null)
Run Code Online (Sandbox Code Playgroud)

以下文本解释了这些命令的工作原理,并强调了旧版本和新版本 OpenSSH 实用程序之间的一些行为差异。

获取公共主机密钥

ssh-keyscan开发该命令的目的是使用户无需向 SSH 服务器进行身份验证即可获取公共主机密钥。从它的手册页:

ssh-keyscan是一个用于收集多个主机的公共 ssh 主机密钥的实用程序。它旨在帮助构建和验证 ssh_known_hosts文件。

钥匙类型

要获取的密钥类型是使用该-t选项指定的。

  • rsa1 (过时的 SSH 协议版本 1)
  • rsa
  • dsa
  • ecdsa (最新版本的 OpenSSH)
  • ed25519 (最新版本的 OpenSSH)

在现代 OpenSSH 版本中,要获取的默认密钥类型是rsa (自 5.1 版起)、ecdsa(自 6.0 版起)和ed25519(自 6.7 版起)。

旧版本ssh-keyscan(OpenSSH的版本5.1)之前,将 默认密钥类型是过时的rsa1(SSH协议1),所以密钥类型将需要明确指定:

ssh-keyscan -t rsa,dsa hostname
Run Code Online (Sandbox Code Playgroud)

获取 Base64 密钥的指纹哈希

ssh-keyscanBase64 编码 格式打印 SSH 服务器的主机密钥。要将其转换为指纹哈希,ssh-keygen可以使用该实用程序及其-l选项来打印指定公钥的指纹。

如果使用 Bash、Zsh(或 Korn shell),进程替换可用于方便的单行:

ssh-keygen -lf <(ssh-keyscan hostname 2>/dev/null)
Run Code Online (Sandbox Code Playgroud)

注意:对于 7.2 之前的 OpenSSH 版本,用于ssh-keygen读取文件的函数 不能很好地处理命名管道 (FIFO),因此该方法不起作用,因此需要使用临时文件。

哈希算法

最新版本的ssh-keygen打印密钥的SHA256指纹哈希。要获取服务器密钥指纹的MD5哈希值(旧行为),该-E 选项可用于指定哈希算法:

ssh-keygen -E md5 -lf <(ssh-keyscan hostname 2>/dev/null)
Run Code Online (Sandbox Code Playgroud)

使用管道

如果使用dash不具有进程替换功能的 POSIX shell(例如),则使用临时文件的其他解决方案将起作用。但是,对于较新版本的 OpenSSH(自 7.2 起),可以使用简单的管道,因为ssh-keygen它将接受-作为标准输入流的文件名,允许单行管道命令。

ssh-keyscan hostname 2>/dev/null | ssh-keygen -E md5 -lf -
Run Code Online (Sandbox Code Playgroud)

  • 似乎不适用于 Ubuntu 14.04 LTS;我收到错误消息“/dev/fd/63 不是公钥文件”。子流程确实有效。 (4认同)
  • @meleb 花了很多时间下载各种源代码版本并在`do_fingerprint()`函数中插入调试`printf`语句后,我发现在OpenSSH 7.2之前的版本中,`ssh-keygen`使用的函数读取文件,不能很好地处理命名管道 (FIFO),因此进程替换方法不起作用。 (3认同)

May*_*ulC 26

当您已经有权访问服务器时,简单的答案是:

\n
ssh-keygen -lf /etc/ssh/ssh_host_rsa_key.pub\n
Run Code Online (Sandbox Code Playgroud)\n
\n

现在,您可能没有使用 RSA 密钥:如果在连接时,ssh告诉您

\n
\n

ECDSA密钥指纹是 SHA256: XXXXX

\n
\n

你需要用/etc/ssh/ssh_host_ecdsa_key.pub它来代替。(注意_ecdsa_)。\n因此可以构造一个列出所有键的更通用的命令(源代码):

\n
for f in /etc/ssh/ssh_host_*_key.pub; do ssh-keygen -lf "$f"; done\n
Run Code Online (Sandbox Code Playgroud)\n

您可以在设置服务器时记下该列表,以供将来参考。另一种选择是将它们存储在 DNS 记录中存档):

\n
    \n
  1. 添加以下 DNS 记录:(<hostname> IN SSHFP <key-type> <hash-type> <fingerprint>如果ssh-keygen您提供主机名,ssh-keygen -r hostname -f /etc/ssh/ssh_host_ecdsa_key.pub则可以为您打印此行:)
  2. \n
  3. ssh -o VerifyHostKeyDNS=yes user@hostname通过添加VerifyHostKeyDNS=yes到客户端配置来连接或默认启用它。
  4. \n
\n
\n

来自 ssh-keygen (1) 联机帮助页:

\n
\n

-l 显示指定公钥文件的指纹。对于 RSA 和 DSA 密钥,ssh-keygen 尝试查找匹配的公钥文件并打印其指纹。如果与 -v 结合使用,密钥的视觉 ASCII 艺术表示将与指纹一起提供。

\n

-f filename\n指定密钥文件的文件名。

\n

-r hostname\n打印指定公钥文件的名为主机名的 SSHFP 指纹资源记录。

\n

-E fingerprint_hash\n指定显示密钥指纹时使用的哈希算法。有效选项为:\xe2\x80\x9cmd5\xe2\x80\x9d 和 \xe2\x80\x9csha256\xe2\x80\x9d。默认值为 \xe2\x80\x9csha256\xe2\x80\x9d。

\n
\n

-E md5从默认打印 md5 密钥的旧版 ssh 客户端连接时,您可能需要使用最后一个选项。或者,从这些客户端,让 ssh 打印 SHA256ssh -o FingerprintHash=sha256 host

\n

  • 这是唯一有用的答案,其他答案只是询问“某个远程主机的密钥是什么”,如果有的话,它将打印 MITM 的密钥……这不是验证主机密钥的好方法,就像问索要你信用卡的人“你是我的银行职员吗?”。 (10认同)
  • @SuzanneSoy是的,您需要使用(并信任)其他一些“渠道”来验证密钥(或其指纹)。我认为这个和其他答案隐含地假设你正在这样做,否则,正如你所指出的,生成/计算密钥的指纹根本没有意义。 (2认同)

Cre*_*eek 22

nmap通过使用ssh-hostkey脚本提供此功能。

返回密钥的十六进制指纹:

$ nmap [SERVER] --script ssh-hostkey
Run Code Online (Sandbox Code Playgroud)

返回密钥的内容:

$ nmap [SERVER] --script ssh-hostkey --script-args ssh_hostkey=full
Run Code Online (Sandbox Code Playgroud)

返回键的可视气泡

$ nmap [SERVER] --script ssh-hostkey --script-args ssh_hostkey='visual bubble'
Run Code Online (Sandbox Code Playgroud)

要返回以上所有内容:

$ nmap [SERVER] --script ssh-hostkey --script-args ssh_hostkey=all
Run Code Online (Sandbox Code Playgroud)

来源:nmap 文档

  • 这些示例是否假设 SSH 始终在端口 22 上运行?如果 ssh 侦听非标准端口怎么办? (3认同)
  • @MartinVegter(转述 Guarin42,无法发表评论:)nmap 具有可以指定端口的 `-p` 选项,例如 `-p 22000`。也可以使用 `-vv` 选项来增加详细程度(提供的信息量) (3认同)
  • 今天尝试了这个 - 没有得到任何脚本承诺/相关的输出,只有 nmap 进度和一般信息。 (2认同)

Cam*_*ron 8

filezilla以十六进制格式显示用 md5 散列的密钥

要在您的ubuntu linux机器上找到它,请使用以下命令:

ssh-keygen -l -E md5 -f <(ssh-keyscan localhost 2>/dev/null)
Run Code Online (Sandbox Code Playgroud)

注意:将“localhost”替换为您要检查的机器的 IP。


ejm*_*ejm 5

这是我编写的一个 shell 脚本(主要是 Bourne shell,但使用local关键字,在大多数现代中都可用)。/bin/sh像这样使用它ssh-hostkey hostname。它将显示给定主机名或 IP 地址的所有主机密钥的 sha256 和 md5 格式指纹。您还可以手动指定“ md5”或“ sha256”作为第二个参数以仅显示该特定格式。

它使用临时文件而不是管道来使其与旧的 OpenSSH 包兼容(如其他答案中所述)。临时文件使用/dev/shm(共享内存)(如果可用)。

#!/bin/sh
usage () {
  printf '%s\n' "Usage: ssh-hostkey HOSTNAME [FPRINTHASH]"
}

ssh_hostkey () {
  local host="$1"
  local fprinthash="$2"
  local tmp=

  case "$host" in
    -h|--help|'')
      usage >&2
      return 1
      ;;
  esac

  case "$fprinthash" in
    md5|sha256|'') true;;
    *)
      usage >&2
      printf '%s\n' "Fingerprint hash may be 'md5' or 'sha256'" >&2
      return 2
      ;;
  esac

  if test -d /dev/shm
  then tmp="$(mktemp -d -p /dev/shm)"
  else tmp="$(mktemp -d)"
  fi

  trap 'trap - INT TERM EXIT; rm -rf "$tmp"' INT TERM EXIT
  ssh-keyscan "$host" > "$tmp/f" 2> /dev/null
  case "$fprinthash" in
    sha256|'') ssh-keygen -l -f "$tmp/f" 2> /dev/null;;
  esac
  case "$fprinthash" in
    md5|'') ssh-keygen -l -E md5 -f "$tmp/f" 2> /dev/null;;
  esac

  trap - INT TERM EXIT
  rm -rf "$tmp" > /dev/null 2>&1
}

ssh_hostkey "$@"
Run Code Online (Sandbox Code Playgroud)