密码学 20:SSH 为什么既有主机密钥,又有登录密钥
连接一台测试服务器,SSH 客户端既要判断“这真是打算连接的那台主机”,又要让服务器判断“这位用户能不能登录”。两种判断都可能用公钥签名,却不意味着两把密钥可以合并:第一道问题由客户端验证服务器,第二道问题由服务器验证用户。如果把 SSH 登录的公钥当成主机身份,网络上的冒充者就能在用户出示登录证据以前让客户端连错服务器。
第一把密钥:连接的是谁
SSH transport 先协商密钥交换算法、主机公钥算法、加密及完整性算法。以 RFC 4253 §8 的 DH 例子说明输入:客户端和服务器各自产生一份不公开的临时指数,交换公有 DH 份额,分别算出相同的 K。这些公有份额不提供身份。服务器还发送公开的主机密钥 K_S,用相应主机私钥对交换摘要 H 签名。
H 不只是“连接上了”这四个字的哈希;例子的输入包含双方版本串、双方算法协商报文、服务器主机公钥、两份交换公有值及共同秘密 K,并按 SSH 字节类型编码。客户端验证签名,也必须从可信途径知道哪把主机公钥属于期望的服务器。本地 pinned known_hosts 是一种来源;主机证书另需明确签发者与适用主机。若首次连接只点“无条件接受任意新主机密钥”,能证明的只是“对方掌握了它刚给出的公钥对应私钥”;中间人可运行自己的 SSH 服务器,生成自己的主机密钥,并对自己的握手摘要正确签名。
1 | |
交换中首次得到的 H 同时成为 SSH 会话标识。它不是固定不变的“服务器 ID”,而是把后续用户认证绑定到这次连接的材料。更新算法要求不能只照 2006 年例子照搬旧算法:RFC 9142 更新了部分 KEX 要求,RFC 8332 给 RSA 主机/用户签名规定 SHA-2 算法。这里的 RFC 4253 DH 例子解释字段和验证顺序,不是让人启用其每个旧算法的生产配置。
第二把密钥:谁可以登录
安全通道建立之后,服务端才可以接收用户认证。RFC 4252 §7 的 publickey 方法是另一条授权链:客户端提交用户名、服务名、认证方法和用户公钥,持有用户私钥签名;服务器检查该用户的公钥是否被允许,再验请求签名。规范签名输入还包含会话标识,因此不能把某次合法用户签名不加区别地移到另一条 SSH 会话里使用。
1 | |
主机公钥用于回答“服务器是谁”,服务端也可能持有许多不同用户的允许登录公钥;它不会因为控制主机私钥就自动代表每位用户签出登录请求。反过来,某用户控制登录私钥也不能因此证明他连接的是正确主机。删除主机公钥的可信绑定,攻击者可伪造一台服务器并接收用户的操作;删除用户公钥的允许表,验证一个合法签名也不能决定这把钥匙是否拥有指定账户权限;删除会话标识的签名绑定,会失去对认证请求所在会话的明确约束。
这个分工可迁移到贯穿案例:浏览器向 HTTPS 服务提交订单时,服务证书帮助客户端认证服务;钱包经 HTTPS RPC 发交易时,RPC 服务身份和交易授权签名同样是不同判断。然而 SSH 用户登录签名不是交易签名;SSH 验证通过不会说明区块链上的 nonce、余额、执行结果、确认状态,更不会说明现实订单交付。
实验:两种错误身份分开失败
examples/cryptography/20_ssh_host_user.py 以固定版本 paramiko==3.5.1 建立真实回环 SSH transport。脚本生成一次性主机密钥及正确/错误用户密钥,给客户端临时 known_hosts 精确钉住本次回环主机公钥,关闭 SSH agent、自动寻找本机用户密钥与“首次连接自动接受”策略。三条路径相同,只有可信输入不同:
- 正确 pinned 主机公钥 + 允许表中的用户密钥:用户登录成功。
- 错的 pinned 主机公钥 + 正确用户密钥:先被客户端的主机身份检查拒绝,不进入成功的用户认证。
- 正确 pinned 主机公钥 + 错的用户密钥:主机正确,服务器仍拒绝用户登录。
先按仓库内 examples/cryptography/README.md 完成环境准备;以下命令从仓库根目录执行。
1 | |
这是临时隔离 venv 的本次路径;其他机器需在自己的隔离环境安装对应版本。2026-10-06 UTC,脚本和 1 项测试退出码均为 0,三个判断都得到预期结果;私钥没有写入仓库或公开输出,pin 文件运行结束后删除。这里是 Paramiko 客户端对 Paramiko 服务端的测试,不是 OpenSSH CLI 互通或真实系统账户授权:当前环境没有 ssh/sshd,这一项仍是 NOT_RUN。实验也没有测试把错误用户公钥写入允许表后的业务权限策略。
两道带答案的练习
画图题: 在两端画出主机私钥、主机可信公钥、用户私钥、用户允许公钥的位置。假设攻击者能更改客户端 known_hosts 为自己的公钥,但拿不到原主机私钥,哪一步还能成功,哪一步已失去预期身份?
可核对答案: 服务端持主机私钥,客户端须从可信配置获得对应公钥;用户持用户私钥,服务端须有这名用户被允许的公钥。若攻击者连同客户端的可信配置一起控制,即使原主机私钥仍安全,攻击者也可以用自己的主机密钥与客户端建立攻击者的合法加密 SSH 通道;签名正确不等于目标身份正确。用户认证是否再被攻破不能仅据此推断。
变更题: 在实验中仅将正确路径的 correct_pin 替换为 incorrect_pin;另一次运行只将正确用户密钥替换为 wrong_user_key。预期分别由谁拒绝?能否把一次登录成功当作合成订单或交易已经提交的证据?
可核对答案: 换错 pin 时由客户端拒绝主机,正常登录正例不再成立;换错用户密钥时由服务器拒绝用户,主机身份检查仍成立。两者都与订单业务、钱包交易及账本确认无关。
资料与导航
- RFC 4253 §7–§8、RFC 4252 §2、§7:会话标识、主机认证和用户公钥认证的精确输入。
- RFC 9142、RFC 8332:交换算法要求更新及 RSA SHA-2 算法。
- 19 QUIC 如何复用 TLS 保护数据包 · 14 证书为何绑定服务名与公钥。




