# 查詢 SSH 服務的公鑰指紋 | 維運猿的共同筆記
供登入人員於建立連線時進行驗證,避免遭受中間人攻擊(MitM attack)
<https://hackmd.io/@ops-notes-tw/query-ssh-public-key-fingerprints>
## 內容大綱
[TOC]
## 如服務基於 OpenSSH
### 檢查方式
於{伺服器|server}之{文字終端|text terminal}中執行下列任一命令有輸出內容:
* `ps aux | grep --color=always 'sshd: ' | grep --invert-match grep 2>/dev/null`
適用於 GNU Coreutils 之 `ps` 命令實作
* `ps w | grep 'sshd: ' | grep -v grep 2>/dev/null`
適用於 busybox 之 `ps` 命令實作。
### 操作流程
1. 透過安全的方式(如臨機操作)取得伺服器的{命令列操作界面|command-line interface}。
1. 切換使用者為 `root`
:::info
**附註:** 此操作的目的為讓使用者可以存取 SSH 服務的私鑰,其僅對 `root` 使用者開放存取(您亦可以使用一般使用者身份存取 SSH 公鑰來得出其指紋,但是伺服器未必會建立 SSH 服務的公鑰檔案故其實行可能性非 100% 故未被本文章使用)。
:::
4. 執行下列命令查詢 SSH 服務的公鑰指紋:
```bash!
# 如檔名展開(filename expansion)沒有任何結果則不產生輸出(預設行為:保留檔名展開的式樣(expression))
shopt -s nullglob
for sshd_host_private_key in /etc/ssh/ssh_host_*_key; do
for fingerprint_algorithm in md5 sha256; do
ssh-keygen -l -E "${fingerprint_algorithm}" -f "${sshd_host_private_key}"
done
done
```
您應可以得到類似下列這樣的命令輸出:
```text
256 MD5:1f:a4:6a:a6:36:f9:a0:0f:7f:64:5d:fe:63:c5:37:92 root@hostname (ECDSA)
256 SHA256:LWq4PlEus50uiiZd3JqCXPHijZX9UGW4L9h5OiBbfkE root@hostname (ECDSA)
256 MD5:93:b6:b5:d1:f8:a0:a3:cd:c1:64:bc:32:01:ac:55:6a root@hostname (ED25519)
256 SHA256:ohr++KpA/+M++vEVYlPDilzgaI8GFCyfykndomKoViQ root@hostname (ED25519)
3072 MD5:96:66:09:2b:ea:7d:eb:b6:28:a5:fa:cc:c7:07:f1:c5 root@hostname (RSA)
3072 SHA256:LLcUaU5fGofvvm6UG9VuOhQ8OjjpqaRTefYubb/c6dM root@hostname (RSA)
```
每一行輸出的格式為:
```text
_加密位元數_ _雜湊演算法_:_公鑰指紋_ _目標主機註解_ (_金鑰對(keypair)類型_)
```
## 如服務基於 Dropbear
### 檢查方式
於{伺服器|server}之{文字終端|text terminal}中執行下列命令有輸出內容:
```shell
ps w | grep 'dropbear' | grep -v grep 2>/dev/null
```
### 操作流程
1. 透過安全的方式(如臨機操作)取得伺服器的{命令列操作界面|command-line interface}。
2. 切換使用者至 `root`
3. 執行下列命令查詢 SSH 服務的公鑰指紋:
```shell
for dropbear_host_private_key in /etc/dropbear/dropbear_*_host_key; do
dropbearkey -y -f "${dropbear_host_private_key}"
done
```
您應可以得到類似下列這樣的命令輸出:
```text
Public key portion is:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMlsXJ23hs04RQm3kA4YfYQGqaNxsqfSjAIsy2MTdd01 root@reMarkable
Fingerprint: sha1!! a5:1f:71:ef:46:17:15:05:3f:53:42:8f:3e:1a:74:27:01:d9:ed:c5
```
輸出的格式如下:
```text
Public key portion is:
ssh-_金鑰對類型_ _公鑰的 Base64 編碼_ _服務註解_
Fingerprint: _產生指紋之雜湊演算法類型_!! _公鑰指紋_
```
:::info
**附註:**
如果您使用 OpenSSH 的客戶端軟體應會發現其提示之 SSH 服務端公鑰指紋與此步驟所列舉之指紋不同,這是因為 Dropbear(公鑰雜湊結果的以冒號分隔之十六進位表示法)與 OpenSSH(公鑰雜湊結果的 base64 編碼)軟體採用不同的公鑰指紋表示法之緣故。
於前述之範例中 OpenSSH 所產生之 SHA-1 金鑰指紋(可使用 `ssh-keyscan _SSH 服務主機地址_ 2>/dev/null | ssh-keygen -lf - -E sha1` 命令產生)為:
```base64
pR9x70YXFQU/U0KPPhp0JwHZ7cU
```
因其為 27 個字元非 4 的倍數故須根據 Base64 編碼要求後綴一個等號將其手動補完為 28 個字元:
```base64
pR9x70YXFQU/U0KPPhp0JwHZ7cU=
```
然後即可使用下列{流水線|pipeline}{命令|command}將其轉換為 Dropbear 的輸出格式:
```bash
printf 'pR9x70YXFQU/U0KPPhp0JwHZ7cU=' \
| base64 --decode \
| xxd -plain \
| sed 's/../&:/g; s/:$//'
```
命令{組成元件|component}說明:
* `base64` 命令的 `--decode` (`-d`) {命令選項|command option}:進行解碼而非編碼操作。
* `xxd` 命令的 `-plain` (`-p`) {命令選項|command option}:使用 plain hex dump 風格輸出輸入資料的{十六進位表示法|hexadecimal representation}。
* `sed` 命令的 `s/../&:/g; s/:$//` {表達式|expression}:
+ `s/../&:/g` 搜尋取代(`s`) `sed` 命令:從輸入的開頭將任意二字元(`..`)替換為其自身(`&`)並後綴一冒號(`:`);對所有比對到搜尋表達式(`..`)的字串都進行此操作(`g`)。
+ `s/:$//` 搜尋取代(`s`) `sed` 命令:將前命令輸出末端之冗餘冒號去掉(替換為空字串)。
即會產生與 Dropbear 軟體一致之結果:
```text!
a5:1f:71:ef:46:17:15:05:3f:53:42:8f:3e:1a:74:27:01:d9:ed:c5
```
:::
## 參考資料
* [ssh-keygen(1) 的 manpage 使用手冊頁面](https://manpages.debian.org/bookworm/openssh-client/ssh-keygen.1.en.html)
說明 `ssh-keygen` 命令下列命令選項之用途:
+ `-l`
+ `-E "${fingerprint_algorithm}"`
+ `-f "${sshd_host_key}"`
* [中間人攻擊 - 維基百科,自由的百科全書](https://zh.wikipedia.org/zh-tw/中间人攻击)
* [dropbearkey(1) — dropbear-bin — Debian bookworm — Debian Manpages](https://manpages.debian.org/bookworm/dropbear-bin/dropbearkey.1.en.html)
說明 `dropbearkey` 命令各命令選項的用途。
* [SSH 服務公鑰指紋主題之 gpt-4-turbo 大語言模型(LLM)對話紀錄 - HackMD](https://hackmd.io/90UK1ykMRayZzmiDFctIXQ)
說明如何使用 Dropbear 軟體查詢 SSH 服務的公鑰指紋,以及如何將 OpenSSH 軟體的 base64 公鑰指紋表示法轉換為 Dropbear 軟體的十六進位公鑰指紋表示法。
* [xxd(1) — manpages-zh — Debian bookworm — Debian Manpages](https://manpages.debian.org/bookworm/manpages-zh/xxd.1.zh_TW.html)
說明 `xxd` 命令 `-p` 命令選項的用途。
---
本作品為[《維運猿的共同筆記》](https://hackmd.io/@ops-notes-tw/home)的一部分
頁面連結:<https://hackmd.io/@ops-notes-tw/query-ssh-public-key-fingerprints>
授權條款:<https://hackmd.io/@ops-notes-tw/licensing>
參與協作視同將您的貢獻內容以相同的授權條款釋出
<style>
/* 調大旁註文字的字元大小 */
rt{
font-size: 10pt;
}
</style>