获取SSH服务器密钥指纹


82

有没有一种方法可以通过编程方式获取SSH服务器密钥指纹而不进行身份验证

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

Answers:


71

您可以通过将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

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


1
也许ssh-keygen -l -f - <(ssh-keyscan host)可以吗?
CVn 2014年

21
OpenSSH> = 7.2 ssh-keyscan可以从标准输入中读取:ssh-keyscan host | ssh-keygen -lf -
mykhal

1
只需:ssh-keygen -l -f <(ssh-keyscan host)
Christopher

1
对于shell脚本来说,这是一个很糟糕的表达,因为它取决于支持它的shell,而POSIX shell却不支持。
安德里亚斯·威斯

2
ssh-keygen -l -f -确实按ssh-keygen 7.2及更高版本中的预期工作。正如Anthony Geoghegan或ssh-keyscan host 2>/dev/null | ssh-keygen -l -f -
Cedric Knight

56

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

ssh-keygen -lf <(ssh-keyscan hostname 2>/dev/null)

下文说明了这些命令的工作方式,并重点介绍了旧版本和较新版本的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

获取Base64密钥的指纹哈希

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

如果使用Bash,Zsh(或Korn Shell),则可以将进程替换用于方便的单行代码:

ssh-keygen -lf <(ssh-keyscan hostname 2>/dev/null)

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

散列算法

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

ssh-keygen -E md5 -lf <(ssh-keyscan hostname 2>/dev/null)

使用管道

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

ssh-keyscan hostname 2>/dev/null | ssh-keygen -E md5 -lf -

好的和彻底的答案,这肯定比拥有临时文件要好!我是否建议您在过程替换版本的开头提供TL; DR,以使不耐烦的人们更快地找到它?:)
goncalopp

3
在Ubuntu 14.04 LTS上似乎不起作用;我收到错误“ / dev / fd / 63不是公共密钥文件”。子过程确实起作用。
梅勒

@melleb我在可以访问的12.04系统上找到了相同的东西。我怀疑ssh-keygen从旧版本的OpenSSH读取FIFO /命名管道时出现问题。有空的时候我会研究这个问题(并更新我的答案)。
Anthony Geoghegan

3
@melleb在花费大量时间下载各种源代码版本并printfdo_fingerprint()函数中插入调试语句后,我发现在7.2之前的OpenSSH版本中,用于ssh-keygen读取文件的函数不能很好地处理命名管道(FIFO)。流程替代方法将不起作用。
Anthony Geoghegan

此方法有效,但是如果使用它来验证指纹,则用户应注意存在竞争状况:使用此命令检查的指纹不一定是所获取密钥的指纹,除非您在调用ssh- Keygen就可以了。
CodeGnome

20

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

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

$ nmap [SERVER] --script ssh-hostkey

要返回密钥的内容:

$ nmap [SERVER] --script ssh-hostkey --script-args ssh_hostkey=full

返回键的可视气泡

$ nmap [SERVER] --script ssh-hostkey --script-args ssh_hostkey='visual bubble'

返回以上所有内容:

$ nmap [SERVER] --script ssh-hostkey --script-args ssh_hostkey=all

资料来源:nmap docs


3
这些示例是否假定SSH始终在端口22上运行?如果ssh在非标准端口上侦听怎么办?
Martin Vegter 2014年

3
@MartinVegter(解释为Guarin42,他无法评论:) nmap具有-p可以指定端口的选项,例如-p 22000。也可以使用该-vv选项来增加详细程度(给定的信息量)
goncalopp 2015年

2

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

要在您的ubuntu linux计算机上找到此命令,请使用以下命令:

ssh-keygen -l -E md5 -f <(ssh-keyscan localhost 2>/dev/null)

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


1

这是我编写的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 "$@"
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.