跳至正文
老丹的足迹 —— 代码写给机器,游记写给自己,感悟写给时间
老丹的足迹 老丹的足迹
老丹的足迹 老丹的足迹
  • 首页
  • 示例页面
  • 首页
  • 示例页面
老丹的足迹 老丹的足迹
老丹的足迹 老丹的足迹
  • 首页
  • 示例页面
  • 首页
  • 示例页面

SSH 算法协商完全解析:密钥交换、主机密钥与加密算法的角色与协作

一、为什么需要算法协商

SSH 客户端和服务器建立连接时,双方可能是不同厂商、不同版本、不同安全策略的实现。它们必须先就”用什么算法来保护这条连接”达成一致。

这个过程就像两个人打电话前先确认:”你听得懂中文吗?听不懂?那英文呢?……” 只有找到双方都支持的语言,对话才能开始。

SSH 协议规定了几个独立的参数维度,每个维度都必须至少有一个双方都支持的选项,否则连接直接失败。核心维度是:

  • 密钥交换算法(KexAlgorithms):双方如何安全地生成共享会话密钥
  • 主机密钥类型(HostKeyAlgorithms):服务器用什么算法证明自己的身份
  • 加密算法(Ciphers):用什么算法加密传输的数据
  • 消息认证码(MACs):用什么算法保证数据完整性

二、如何查看客户端支持的算法

2.1 ssh -Q 系列命令

ssh -Q 用于查询客户端编译时支持的算法列表:

ssh -Q kex        # 密钥交换算法
ssh -Q key        # 主机密钥/用户密钥类型
ssh -Q cipher     # 加密算法
ssh -Q mac        # 消息认证码算法
ssh -Q help       # 列出所有可用的 -Q 参数

关键理解:ssh -Q 回答的是”这个 SSH 二进制文件里编译进去了什么”,不等于“默认启用了什么”。不安全的算法可能被编译进去以保持兼容性,但默认是关闭的。

2.2 查看默认实际启用的算法

ssh -Q 没有 -default 后缀参数(ssh -Q kex-default 会报错)。要看客户端实际会优先提出哪些算法,用 ssh -G:

ssh -G example.com | grep -i kexalgorithms
ssh -G example.com | grep -i hostkeyalgorithms
ssh -G example.com | grep -i ciphers
ssh -G example.com | grep -i macs

ssh -G 会应用所有配置文件后,打印出针对目标主机最终生效的配置。输出中排在第一位的算法就是客户端连接时会优先提出的选项。

2.3 查看真实连接协商结果

ssh -vv user@host 2>&1 | grep -E "kex: algorithm|kex: host key algorithm"

这会显示这条连接最终协商出的 KEX 算法和主机密钥算法,是最直接的答案。

三种查询方式对比:

命令回答的问题
ssh -Q kex客户端支持哪些算法
ssh -G host客户端默认优先提出哪些算法
ssh -vv host这条连接实际协商出什么算法

三、密钥交换算法(Key Exchange Algorithms)

3.1 它解决什么问题

在 SSH 连接建立的最初阶段,双方需要在一条不安全的网络上,安全地协商出一个只有双方知道的共享会话密钥。这个会话密钥将用于后续所有数据的加密。

密钥交换算法基于 Diffie-Hellman 密钥交换或其变体。DH 的核心思想是:

  1. 双方各自生成一个临时私密值。
  2. 双方交换由私密值计算出的公开参数。
  3. 双方各自用”自己的私密值 + 对方的公开参数”计算出相同的共享密钥。
  4. 窃听者只能看到公开参数,无法推导出共享密钥。

这个共享密钥就是后续加密用的会话密钥。

3.2 Diffie-Hellman 的变体

纯 DH 有几个问题:容易受中间人攻击、计算开销大、群参数可能不安全。因此演化出多种变体:

变体原理优点
ECDH用椭圆曲线代替有限域密钥更短,性能更好
Curve25519特定椭圆曲线,专为 ECDH 设计高速、抗侧信道攻击
DH Group Exchange动态协商 DH 群大小避免固定群被预计算攻击
混合抗量子传统 ECDH + 后量子算法抵御未来量子计算机威胁

3.3 客户端支持列表解读

以下是你客户端 ssh -Q kex 的输出:

默认启用(现代、安全)

算法原理与说明
sntrup761x25519-sha512@openssh.com混合抗量子算法:sntrup761(后量子)+ x25519(经典 ECDH)。即使未来量子计算机破解了 x25519,sntrup761 仍能保护。OpenSSH 新版本首选
curve25519-sha256基于 Curve25519 的 ECDH,性能与安全俱佳,无已知弱点
curve25519-sha256@libssh.org同上的早期变体,仍广泛支持
ecdh-sha2-nistp256/384/521基于 NIST 素域曲线的 ECDH。P-256/384/521 分别对应 128/192/256 位安全强度
diffie-hellman-group-exchange-sha256可动态协商 DH 群大小,避免固定群被预计算
diffie-hellman-group16-sha5124096 位 DH 群,SHA-512 哈希
diffie-hellman-group18-sha5128192 位 DH 群,SHA-512 哈希
diffie-hellman-group14-sha2562048 位 DH 群,SHA-256 哈希,IETF 标记为 MUST 支持

默认禁用(编译进去但不启用)

算法问题
diffie-hellman-group1-sha11024 位 DH 群,易受 Logjam 攻击(预计算后快速破解)
diffie-hellman-group14-sha1SHA-1 哈希,已不推荐
diffie-hellman-group-exchange-sha1SHA-1 哈希,已不推荐

关键点:ssh -Q kex 列出 diffie-hellman-group1-sha1,不代表客户端会用它。只有显式配置 KexAlgorithms +diffie-hellman-group1-sha1 时才会启用。

四、主机密钥类型(Host Key Types / HostKeyAlgorithms)

4.1 它解决什么问题

当客户端决定信任一个服务器时,需要验证”这个服务器确实是它声称的那台机器,而不是中间人伪装的”。

服务器通过出示自己的主机密钥来证明身份。主机密钥类型参数决定了客户端接受服务器用哪种算法生成这个身份证明。

4.2 主机密钥的工作原理

  1. 服务器上有一对主机密钥(私钥 + 公钥),私钥只有服务器知道。
  2. 连接时,服务器把主机公钥发给客户端。
  3. 服务器用主机私钥对密钥交换过程中的数据签名。
  4. 客户端用主机公钥验证签名,确认服务器持有对应的私钥。
  5. 客户端检查这个公钥是否与 ~/.ssh/known_hosts 中记录的一致。

4.3 各算法类型详解

算法数学基础密钥长度安全性推荐状态
Ed25519Edwards 曲线(Curve25519 的变体)固定 256 位约等于 RSA 3072首选,性能与安全最佳
ECDSANIST 素域曲线256/384/521 位分别约等于 RSA 3072/7680/15360可用,NIST 曲线有争议
RSA大整数分解2048-16384 位2048 位约等于 112 位安全强度兼容性最强,新环境不首选
DSA离散对数固定 1024 位仅约 80 位安全强度已弃用

4.4 客户端支持列表解读

以下是你客户端 ssh -Q key 的输出:

普通密钥类型

算法状态
ssh-ed25519默认启用,首选
ecdsa-sha2-nistp256/384/521默认启用
ssh-rsa默认禁用(OpenSSH 8.8+),仅兼容旧服务器时手动启用。原因是 SHA-1 签名已被认为不安全
ssh-dss默认禁用(OpenSSH 7.0+),DSA 已废弃

证书类型(-cert-v01@openssh.com 后缀)

这些是 SSH 证书用的密钥类型。SSH 证书是一种比 authorized_keys 更中心化的信任管理方式:由 CA(证书颁发机构)签发证书,服务器信任 CA 即可,不用逐个添加公钥。

算法说明
ssh-ed25519-cert-v01@openssh.comEd25519 证书
ecdsa-sha2-nistp256-cert-v01@openssh.comECDSA 证书
ssh-rsa-cert-v01@openssh.comRSA 证书
ssh-dss-cert-v01@openssh.comDSA 证书(已废弃)

FIDO/U2F 安全密钥类型(sk- 前缀)

sk- = security key,指硬件安全密钥(如 YubiKey)。

算法说明
sk-ssh-ed25519@openssh.comEd25519 硬件密钥
sk-ecdsa-sha2-nistp256@openssh.comECDSA 硬件密钥

这些用于物理硬件密钥,登录时需要触碰硬件才能完成认证,安全性更高。

4.5 主机密钥从哪来

服务器上的主机密钥位于 /etc/ssh/,命名格式为 ssh_host_<类型>_key(私钥)和 .pub(公钥)。安装 openssh-server 时会自动生成一组。

客户端首次连接服务器时,会收到服务器的主机公钥。确认指纹后,该公钥保存在 ~/.ssh/known_hosts。后续连接时,客户端会检查服务器出示的主机密钥是否与 known_hosts 中记录的一致,不一致则发出严重警告。

五、加密算法(Ciphers)

5.1 它解决什么问题

会话密钥协商完成后,SSH 连接上传输的所有数据(密码、命令、文件内容)都需要被加密。加密算法参数决定了用哪种对称加密算法来保护数据流。

5.2 对称加密的两种模式

模式全称特点
CTRCounter Mode把块密码变成流密码,每个块用递增计数器加密。需要额外的 MAC 保证完整性
GCMGalois/Counter ModeCTR + GMAC 认证,同时提供加密和完整性。属于 AEAD
CBCCipher Block Chaining每个块与前一个密文块异或。易受填充 oracle 攻击,已不推荐

5.3 AEAD 是什么

AEAD(Authenticated Encryption with Associated Data,带关联数据的认证加密) 是一种同时提供机密性和完整性的加密方案。

传统模式(如 CBC、CTR)只负责加密,完整性要另加 MAC。AEAD 把两者合一,更安全也更高效。

chacha20-poly1305 和 aes*-gcm 都是 AEAD 算法。

5.4 客户端支持列表解读

以下是你客户端 ssh -Q cipher 的输出:

默认启用(AEAD 类算法)

算法原理与说明
chacha20-poly1305@openssh.comChaCha20 流加密 + Poly1305 认证。在无 AES 硬件加速的平台上性能极佳。注意:Terrapin 攻击论文指出其存在序列号操纵风险,缓解措施是实现 strict-kex
aes256-gcm@openssh.comAES-256 + GCM 认证模式。Intel 平台有 AES-NI 硬件加速
aes128-gcm@openssh.comAES-128 + GCM,同上但密钥较短
aes256-ctrAES-256 计数器模式,需配合 MAC 算法保证完整性
aes192-ctrAES-192 计数器模式
aes128-ctrAES-128 计数器模式

默认禁用(CBC 模式,不安全)

算法问题
aes256-cbc / aes192-cbc / aes128-cbcCBC 模式易受填充 oracle 攻击(如 Lucky13)
3des-cbc3DES 效率低,且已被认为强度不足

注意:你的输出中没有 des-cbc,说明客户端已彻底移除最弱的 DES。

六、消息认证码(MACs)

6.1 它解决什么问题

MAC 用于保证数据完整性,防止传输过程中被篡改。

在非 AEAD 加密算法(如 aes*-ctr)下,MAC 是独立的一层保护:发送方对数据算一个认证标签,接收方验证标签。如果数据被篡改,标签对不上。

6.2 ETM 模式

-etm@openssh.com 后缀表示 Encrypt-then-MAC(先加密再认证)。

模式流程安全性
MAC-then-Encrypt先算 MAC,再加密(MAC 和数据一起加密)较弱,易受填充攻击
Encrypt-then-MAC先加密,再对密文算 MAC推荐,更安全
Encrypt-and-MAC同时加密和算 MAC,分别发送较弱

ETM 模式更安全,因为接收方可以先验证 MAC 再解密,避免对恶意构造的密文进行解密操作。

6.3 客户端支持列表解读

以下是你客户端 ssh -Q mac 的输出:

ETM 模式(Encrypt-then-MAC,推荐)

算法说明
hmac-sha2-256-etm@openssh.comSHA-256 + ETM,推荐
hmac-sha2-512-etm@openssh.comSHA-512 + ETM,推荐
umac-128-etm@openssh.comUMAC-128 + ETM,基于通用哈希,速度快
umac-64-etm@openssh.comUMAC-64 + ETM
hmac-sha1-etm@openssh.comSHA-1 + ETM,较弱
hmac-sha1-96-etm@openssh.comSHA-1 截断到 96 位 + ETM,弱
hmac-md5-etm@openssh.comMD5 + ETM,已不安全
hmac-md5-96-etm@openssh.comMD5 截断 + ETM,已不安全

非 ETM 模式(传统,较弱)

算法说明
hmac-sha2-256SHA-256,推荐
hmac-sha2-512SHA-512,推荐
umac-128@openssh.comUMAC-128
umac-64@openssh.comUMAC-64
hmac-sha1SHA-1,较弱
hmac-sha1-96SHA-1 截断,弱
hmac-md5MD5,已不安全
hmac-md5-96MD5 截断,已不安全

关键点:hmac-md5、hmac-sha1 虽然编译进去了,但默认不启用。现代 OpenSSH 默认只用 hmac-sha2-* 和 umac-* 的 ETM 版本。

七、known_hosts 与主机密钥变更

7.1 known_hosts 是什么

~/.ssh/known_hosts 是客户端保存已信任服务器主机公钥的文件。首次连接某台服务器时,客户端会问:

The authenticity of host 'server (10.0.0.1)' can't be established.
ED25519 key fingerprint is SHA256:vuKnvrpcVAk2nu0W5zM2Kqdi48TTY/2TDNiMjSRbN8Q.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

你输入 yes 后,服务器的主机公钥就被写入 known_hosts。下次再连,客户端自动比对,不再询问。

7.2 每行记录的结构

server,10.0.0.1 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... 
└──────┬──────┘ └────┬────┘ └──────────┬──────────┘
   主机名/IP        密钥类型        公钥数据
  • 主机名和 IP 用逗号分隔,表示同一个主机
  • 可以有多行,对应不同算法类型(ed25519、ecdsa、rsa)
  • 如果主机名被哈希处理(HashKnownHosts yes),第一段会变成乱码

7.3 主机密钥变更时会怎样

当服务器重装、升级、或更换主机密钥后,你再次连接会看到:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
...
Offending ED25519 key in /home/user/.ssh/known_hosts:5

这是 SSH 在保护你:新指纹和旧记录不一致,无法确认服务器身份。

7.4 什么时候该删除旧记录

两种情况:

情况一:服务器确实重装了(合法变更)

你确认服务器被重装/换密钥了,就该删除旧记录,重新信任新公钥:

ssh-keygen -R 10.0.0.1
ssh-keygen -R server.example.com

然后重新连接,会再次提示确认新指纹。

情况二:服务器没动过(可能是中间人攻击)

如果你没有重装服务器、没有换密钥,却收到这个警告——千万别直接删记录。这可能是中间人攻击。先用别的方式联系管理员,确认服务器主机密钥到底有没有变。

7.5 实用命令

# 删除指定主机的旧记录
ssh-keygen -R 10.0.0.1

# 查看 known_hosts 中某主机的记录
ssh-keygen -F 10.0.0.1

# 手动查看 known_hosts
cat ~/.ssh/known_hosts

# 查看某主机的指纹(重新连接时对比)
ssh-keyscan -t ed25519 10.0.0.1 | ssh-keygen -lf -

ssh-keyscan 可以从服务器抓取当前主机公钥,配合 ssh-keygen -lf 算出指纹,用于对比。

八、ssh_config 与 sshd_config 常用指令

8.1 客户端配置文件

客户端配置分两层:

文件作用范围
/etc/ssh/ssh_config全局,影响所有用户
~/.ssh/config用户级,只影响当前用户,优先级更高

8.2 客户端常用指令

指令作用示例
Host匹配目标主机,后面跟的配置只对此主机生效Host old-server
HostName实际连接的主机名/IPHostName 10.0.0.1
User登录用户名User richard
Port端口Port 2222
IdentityFile指定私钥文件IdentityFile ~/.ssh/id_ed25519
KexAlgorithms密钥交换算法KexAlgorithms +diffie-hellman-group1-sha1
HostKeyAlgorithms主机密钥算法HostKeyAlgorithms +ssh-rsa
Ciphers加密算法Ciphers +aes128-cbc
MACs消息认证码MACs +hmac-sha1
PubkeyAcceptedAlgorithms用户公钥认证算法PubkeyAcceptedAlgorithms +ssh-rsa
StrictHostKeyChecking主机密钥检查策略StrictHostKeyChecking ask
ServerAliveInterval心跳间隔(秒)ServerAliveInterval 60

8.3 算法配置的前缀语法

配置算法列表时,前缀决定是追加还是替换:

前缀含义示例
无前缀替换整个默认列表Ciphers aes128-ctr
+追加到默认列表末尾Ciphers +aes128-cbc
-从默认列表中移除Ciphers -aes128-ctr
^把指定算法移到列表最前Ciphers ^aes128-ctr

推荐用 +,因为这样不会破坏默认的安全列表,只是把旧算法补充进去。

8.4 服务端配置文件

文件作用
/etc/ssh/sshd_config服务端主配置
/etc/ssh/sshd_config.d/*.conf额外配置片段(较新版本支持)

8.5 服务端常用指令

指令作用
Port监听端口
ListenAddress监听地址
HostKey指定主机私钥文件
KexAlgorithms允许的密钥交换算法
HostKeyAlgorithms允许的主机密钥算法
Ciphers允许的加密算法
MACs允许的 MAC 算法
PubkeyAuthentication是否启用公钥认证
PasswordAuthentication是否启用密码认证
PermitRootLogin是否允许 root 登录
AllowUsers / DenyUsers用户访问控制

8.6 查看服务端实际生效的配置

# 打印最终生效的完整配置
sudo sshd -T

# 只看算法相关
sudo sshd -T | grep -iE "kexalgorithms|hostkeyalgorithms|ciphers|macs"

# 检查配置文件语法
sudo sshd -t

sshd -T 会把所有 include、默认值合并后,输出真正生效的配置,比直接看 sshd_config 更准确。

九、ssh -vv 实际输出解读

9.1 为什么要看 -vv

ssh -Q 只告诉你”支持什么”,ssh -G 只告诉你”默认提案什么”。这条连接到底协商出了什么,只有 -vv 能看到。

9.2 一段真实的协商日志

ssh -vv user@10.0.0.1

输出中与算法协商相关的关键行(已简化):

debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug2: local client KEXINIT proposal
debug2: KEX algorithms: sntrup761x25519-sha512@openssh.com,curve25519-sha256,...
debug2: host key algorithms: ssh-ed25519,ecdsa-sha2-nistp256,...
debug2: ciphers ctos: chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,...
debug2: ciphers stoc: chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,...
debug2: MACs ctos: umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,...
debug2: MACs stoc: umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,...

debug2: peer server KEXINIT proposal
debug2: KEX algorithms: curve25519-sha256,ecdh-sha2-nistp256,...
debug2: host key algorithms: rsa-sha2-512,rsa-sha2-256,ssh-ed25519,...
debug2: ciphers ctos: chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,...
debug2: MACs ctos: umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,...

debug1: kex: algorithm: curve25519-sha256
debug1: kex: host key algorithm: ssh-ed25519
debug1: kex: server->client cipher: chacha20-poly1305@openssh.com MAC: <implicit> compression: none
debug1: kex: client->server cipher: chacha20-poly1305@openssh.com MAC: <implicit> compression: none

9.3 逐段解读

第一段:local client KEXINIT proposal

这是你的客户端发出的提案列表。每一行对应一个维度:

  • KEX algorithms:客户端支持的密钥交换算法,按优先级排列
  • host key algorithms:客户端接受的主机密钥算法
  • ciphers ctos / stoc:客户端到服务器(ctos)、服务器到客户端(stoc)两个方向的加密算法
  • MACs ctos / stoc:两个方向的消息认证码

第二段:peer server KEXINIT proposal

这是服务器发回的提案列表。格式同上。

第三段:kex: algorithm 等行

这是最终协商结果,最关键:

行含义
kex: algorithm: curve25519-sha256密钥交换算法最终选了 curve25519-sha256
kex: host key algorithm: ssh-ed25519主机密钥算法最终选了 ssh-ed25519
kex: server->client cipher: chacha20-poly1305@openssh.com服务器到客户端方向用 chacha20-poly1305
kex: client->server cipher: chacha20-poly1305@openssh.com客户端到服务器方向用 chacha20-poly1305
MAC: <implicit>因为 chacha20-poly1305 是 AEAD,MAC 已内置,所以显示 <implicit>

9.4 协商结果怎么定的

双方各自发出提案列表后,从客户端列表的第一项开始,逐个检查服务器是否也支持。第一个双方都支持的算法,就是最终结果。

所以:

  • 客户端提案顺序决定优先级
  • 服务器只需要”支持”即可,不需要排在前面
  • 如果客户端首选 sntrup761x25519-sha512,但服务器不支持,就试下一个,直到找到共同支持的

9.5 常用过滤命令

# 只看最终协商结果
ssh -vv user@host 2>&1 | grep "kex:"

# 看双方提案
ssh -vv user@host 2>&1 | grep -E "KEXINIT proposal|KEX algorithms|host key algorithms"

# 看完整协商日志
ssh -vv user@host 2>&1 | less

十、SSH 证书(Certificate)

10.1 为什么需要证书

传统 authorized_keys 方式的问题是:每台服务器、每个用户,都要手动添加公钥。当服务器有几百台、用户有几千人时,管理成本极高。

SSH 证书用 CA(证书颁发机构) 解决这个问题:

  • CA 生成一对密钥(CA 私钥 + CA 公钥)
  • 用户把自己的公钥交给 CA,CA 用私钥签一张证书(公钥 + 身份信息 + 有效期 + 签名)
  • 服务器配置信任 CA 公钥(TrustedUserCAKeys)
  • 用户登录时出示证书,服务器验证证书由可信 CA 签发即可,不需要逐个添加用户公钥

10.2 证书类型

SSH 证书分两种:

类型用途签发对象
用户证书用户登录服务器用户的公钥
主机证书服务器向客户端证明身份服务器的主机公钥

10.3 用户证书签发流程

第一步:CA 生成密钥对(只做一次)

ssh-keygen -t ed25519 -f ~/.ssh/ca_user_key -C "User CA"

生成 ca_user_key(CA 私钥,必须严格保管)和 ca_user_key.pub(CA 公钥)。

第二步:用户生成自己的密钥对

ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519

第三步:CA 用私钥给用户公钥签证书

ssh-keygen -s ~/.ssh/ca_user_key \
    -I "richard@example.com" \
    -n richard,ubuntu \
    -V +52w \
    ~/.ssh/id_ed25519.pub
参数含义
-sCA 私钥
-I证书标识(Key ID),写谁申请的都行
-n允许登录的用户名列表(principal)
-V有效期,+52w 表示 52 周

生成 ~/.ssh/id_ed25519-cert.pub,这就是证书。

第四步:服务器信任 CA

在服务器的 /etc/ssh/sshd_config 中:

TrustedUserCAKeys /etc/ssh/ca_user_key.pub

把 CA 公钥放到服务器上,重启 sshd。

第五步:用户登录

ssh richard@server

客户端自动使用 id_ed25519 + id_ed25519-cert.pub 完成认证,不需要在服务器上添加 authorized_keys。

10.4 主机证书签发流程

第一步:CA 生成主机 CA 密钥(只做一次)

ssh-keygen -t ed25519 -f ~/.ssh/ca_host_key -C "Host CA"

第二步:给服务器的主机公钥签证书

在服务器上:

sudo ssh-keygen -s ~/.ssh/ca_host_key \
    -I "server.example.com" \
    -h \
    -n server.example.com,10.0.0.1 \
    -V +52w \
    /etc/ssh/ssh_host_ed25519_key.pub
参数含义
-h表示签的是主机证书(不是用户证书)
-n主机名/IP 列表

生成 /etc/ssh/ssh_host_ed25519_key-cert.pub。

第三步:客户端信任主机 CA

在客户端的 ~/.ssh/known_hosts 中添加:

@cert-authority *.example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5...

@cert-authority 表示”这个 CA 签的主机证书我都信”。

第四步:连接

客户端连服务器时,服务器出示主机证书,客户端验证证书由可信 CA 签发,不再需要每次确认指纹。

10.5 证书 vs authorized_keys

authorized_keysSSH 证书
信任方式逐个添加公钥信任 CA 即可
管理成本用户多、服务器多时极高低,只需管理 CA
有效期无,永久有效可设有效期,自动过期
吊销手动删除对应行维护 KRL(Key Revocation List)
适用规模小规模中大规模

10.6 查看证书内容

ssh-keygen -Lf ~/.ssh/id_ed25519-cert.pub

输出会显示证书的 Key ID、有效期、principal、签名等信息。

十一、Terrapin 攻击与 strict-kex

11.1 Terrapin 是什么

Terrapin(CVE-2023-48795)是 2023 年底公开的一种 SSH 协议层攻击。它不破解加密,而是通过操纵握手阶段的序列号,在特定条件下让攻击者能注入或删除加密流量中的部分消息。

11.2 攻击原理

SSH 的二进制数据包协议(Binary Packet Protocol)在握手阶段使用的某些模式(如 chacha20-poly1305 和 *-etm MAC)下,序列号参与完整性校验的方式存在弱点。

攻击者作为中间人,可以:

  1. 在握手阶段篡改扩展协商消息(如 SSH2_MSG_EXT_INFO)。
  2. 通过删除或注入特定消息,使双方对序列号的计数产生偏差。
  3. 在偏差被”吸收”后,攻击者可以注入或删除后续的加密消息。

关键限制:攻击者不能解密流量,只能在特定条件下注入或删除消息。

11.3 哪些算法受影响

类别受影响
chacha20-poly1305@openssh.com是
*-etm@openssh.com MAC是
aes*-gcm@openssh.com是
非 ETM 的 hmac-*否
aes*-ctr + 非 ETM MAC否

11.4 strict-kex 缓解机制

OpenSSH 9.6 引入了 strict-kex(严格密钥交换)作为缓解措施。

原理:双方在握手阶段协商一个信号名 kex-strict-c-v00@openssh.com(客户端)和 kex-strict-s-v00@openssh.com(服务器)。如果双方都支持,就启用严格模式:

  • 序列号在握手阶段不允许出现任何空隙
  • 任何序列号不连续的情况都视为攻击,立即断开连接
  • 攻击者无法在不被发现的情况下操纵序列号

11.5 怎么确认自己是否受保护

ssh -vv user@host 2>&1 | grep -i strict

如果输出中有:

debug1: kex: strict KEX enabled

或协商列表中包含 kex-strict-*,说明已启用 strict-kex。

11.6 建议

  • 升级 OpenSSH 到 9.6 或更高版本,自动启用 strict-kex
  • 如果暂时无法升级,在 ~/.ssh/config 中优先使用非 ETM 的 MAC(如 hmac-sha2-256)配合 aes*-ctr,可避开 Terrapin 攻击面
  • 但这只是权宜之计,升级才是根本方案

十二、协商过程:一次典型的 SSH 握手

当你执行 ssh user@host 时,以下步骤依次发生:

第一步:协议版本交换
客户端和服务器互报支持的 SSH 协议版本。

第二步:算法协商
双方各自发送一个”提案”列表,包含自己支持的 KexAlgorithms、HostKeyAlgorithms、Ciphers、MACs。双方从对方的列表中各自选择最优的、自己也能接受的算法组合。

第三步:密钥交换
使用协商出的密钥交换算法,双方安全地生成一个共享的会话密钥。

第四步:主机密钥验证
服务器用主机私钥对交换过程中的某些数据签名,发送给客户端。客户端用协商出的主机密钥算法对应的公钥验证签名,确认服务器身份。

第五步:用户认证
在已加密且已验证服务器身份的信道上,进行用户身份认证(密码或用户密钥)。

第六步:会话建立
认证通过后,SSH 会话正式建立,后续所有通信都用协商出的加密算法保护。

如果任何一步的算法协商找不到共同支持的选项,连接就会失败,并显示 no matching ... found 错误。

十三、当协商失败时:配置与兼容

13.1 连接老旧服务器

新版 OpenSSH 默认禁用了一些不安全的旧算法。当你需要连接一台老服务器时,可能会遇到:

Unable to negotiate with 10.0.0.1: no matching key exchange method found.
Their offer: diffie-hellman-group1-sha1

解决方案是在 ~/.ssh/config 中为特定服务器启用旧算法:

Host old-server
    HostName 10.0.0.1
    KexAlgorithms +diffie-hellman-group1-sha1
    HostKeyAlgorithms +ssh-rsa
    Ciphers +aes128-cbc
    MACs +hmac-sha1

+ 前缀表示追加到默认列表,而不是替换。这样当服务器升级支持新算法后,会自动使用更优的选项。

13.2 安全提醒

启用旧算法会降低连接安全性。这只是权宜之计,根本方案是升级服务器端的 SSH 服务。

十四、总结

14.1 四个维度速查

维度查询命令默认启用首选
密钥交换ssh -Q kexsntrup761x25519-sha512、curve25519-sha256
主机/用户密钥ssh -Q keyssh-ed25519、ecdsa-sha2-nistp256
加密ssh -Q cipherchacha20-poly1305、aes256-gcm
消息认证ssh -Q machmac-sha2-256-etm、umac-128-etm

14.2 核心结论

ssh -Q 列出的是”这个二进制里有什么”,不是”默认用什么”。默认启用列表是它的子集。旧算法编译进去是为了兼容性,默认关闭是为了安全性。

三种查询方式各司其职:

命令回答的问题
ssh -Q kex客户端支持哪些算法
ssh -G host客户端默认优先提出哪些算法
ssh -vv host这条连接实际协商出什么算法

这三者结合,才能完整回答”我的 SSH 连接到底用了什么算法保护”这个问题。

14.3 安全性排序总览

维度首选可用已弃用
密钥交换sntrup761x25519-sha512、curve25519-sha256ecdh-sha2-*、dh-group16/18-sha512dh-group1-sha1、dh-group14-sha1
主机密钥ssh-ed25519ecdsa-sha2-*、rsa-sha2-512/256ssh-rsa、ssh-dss
加密chacha20-poly1305、aes256-gcmaes*-ctraes*-cbc、3des-cbc
消息认证hmac-sha2-*-etm、umac-*-etmhmac-sha2-*、umac-*hmac-md5*、hmac-sha1*

14.4 相关工具速查

命令用途
ssh -Q kex/key/cipher/mac查看客户端支持的算法
ssh -G host查看客户端默认优先提出的算法
ssh -vv host查看实际协商结果
sshd -T查看服务端生效配置
ssh-keygen -R host删除 known_hosts 中某主机的旧记录
ssh-keygen -F host查询 known_hosts 中某主机的记录
ssh-keyscan host从服务器抓取主机公钥
ssh-keygen -lf key.pub查看密钥指纹
ssh-keygen -Lf cert.pub查看证书内容
作者

老丹

关注我
其他文章
上一个

TPM 2.0 在 Linux 上的工具链:tpm2-tss 与 tpm2-tools 深度解析

下一个

OpenWrt 固件签名三剑客:usign、ucert 与 fwtool 深度解析

关于博主

    老丹是一名C/C++后台开发工程师,信奉“无抽象不设计,无性能不生产”。

  • 技术栈:Modern C++、Linux环境编程、多线程/并发、网络编程等。
  • 信条:能用constexpr解决的问题绝不拖到运行时,能靠RAII避免的泄漏绝不写析构。
  • 正在填坑:从解封装到渲染的C++全链路实现,正在驯服FFmpeg与H.264/H.265。
  • 输出原则:这里的每一段代码都经过-Wall -Wextra -Werror -O2的洗礼。

近期文章

  • 在 Windows 里养一只 Linux:WSL 完整指南 2026年10月24日
  • Paho MQTT C 与 C++ 客户端库完全指南:从概念到 Ubuntu 26.04 下的编译、安装与使用 2026年10月23日
  • Mosquitto $SYS 主题详解:Broker 自监控指南 2026年10月23日
  • 应用级 MQTT 服务搭建完全指南:Mosquitto + 宿主机 Nginx 2026年10月22日
  • OpenWrt 固件签名三剑客:usign、ucert 与 fwtool 深度解析 2026年10月21日

文章分类

  • C/C++开发 (22)
  • Docker容器 (5)
  • Linux工具包 (21)
  • Linux服务配置 (53)
  • Linux系统 (16)
  • MQTT技术 (6)
  • OpenWrt路由 (5)
  • Shell脚本 (3)
  • 代码管理 (1)
  • 安防技术 (4)
  • 数据安全 (36)
  • 网络协议 (25)
  • 计算机理论 (23)
  • 问题解决 (3)
  • 防火墙 (6)
  • 音视频技术 (6)
联系我们:📍 地址:中国·广东省深圳市   |   ✉️ 邮箱:support@tanglinux.com   |   💬 QQ:870866607
版权所有:老丹的足迹粤ICP备2026061170号-1       公安备案图标 粤公网安备44030002013274号