摘要

  • 首次密钥交换产生共享秘密 K 与交换哈希 H。首个 H 由双方实际协商的 transcript 计算而来,成为这条连接的会话标识,不是谁单方面填写的编号。
  • rekey 可以更换算法、流量密钥、初始化向量、压缩上下文,甚至服务器主机密钥,但不会改写最初的会话标识。保护手段更新,不等于上层会话重生。
  • 公钥用户认证会把会话标识、账户、服务、方法、算法与公钥一并签名。它阻止跨连接重放,却不自动授予 shell、端口转发或其他操作权限。

一条长连接里有两种寿命

远程终端可能开上数小时,文件与转发通道也可能长期存在。承载这些状态的会话需要连续;保护数据包的加密材料则不应被迫活得同样久。

若每次换密钥都算新会话,上层必须重建所有通道。若只把新密钥视作新的身份,又会让此前完成的用户认证与换钥后的流量失去明确联系。SSH 需要同时表达两件事:保护已经更新,谈话仍是原来那一场。

RFC 4251 把 SSH 2 划成三层。传输层验证服务器并提供机密性与完整性;用户认证层验证客户端一侧的用户;连接层再复用多个 shell、子系统与转发通道。这种分工决定了 rekey 所在的边界:它改的是传输保护,不该擅自重置上层已经建立的语境。

标识不是报出来的,而是算出来的

客户端与服务器各发一份 SSH_MSG_KEXINIT。其中有随机 cookie,也有按偏好排列的密钥交换、主机密钥、加密、完整性与压缩算法列表。协议按规则选择客户端最靠前、服务器也支持的共同项。

随后,选定的密钥交换方法产生共享秘密 K 与交换哈希 H。在 SSH 2 最初规定的有限域 Diffie–Hellman 方案中,H 覆盖双方版本标识、两份未经重写的 KEXINIT、服务器主机公钥、双方临时值以及共享秘密。

这意味着,改动版本、算法提议、主机密钥或临时值,都会得到不同的 transcript。H 不是服务器发给客户端的一张“会话票”,也不是客户端自称的关联号。双方输入共同塑造它,任何一方都不能单独宣布另一场交换与本场相同。

随机 cookie 增加不可预先决定性,但 H 也不是秘密凭证。会话标识可以公开;知道它并不能推回 K,更不能生成有效的加密或完整性保护。

服务器会用协商出的主机私钥签署交换哈希。验证通过,只能证明那把私钥的持有者签过这份交换记录。它并不会凭空证明公钥属于用户原本想连接的主机名。客户端仍要依据已保存的主机密钥、证书、人工核对的指纹或其他信任政策完成“名称—密钥”关联。密码学正确的陌生密钥,仍可能来自错误的机器。

只有第一个 H 获得了会话身份

RFC 4253 规定,每次交换的 K 与 H 都参与派生保护材料;但只有首次交换的 H 还会成为 session_id。一旦形成,这个标识在连接存续期间不再改变。

rekey 本身可以很彻底。任一端都能发起;算法可以更换,主机密钥也可能变化;密钥与初始化向量重新计算;跨过 SSH_MSG_NEWKEYS 后,加密与压缩上下文被重置。新的交换当然会有新的 K 和 H,但新的 H 不接管会话身份。

这个不变量没有宣称“什么都没变”。意外出现的新主机密钥需要重新评估信任,弱算法可能违反本地政策,失败的 rekey 也会终止连接。它只把结论限制在正确的一层:一次成功的传输更新,不会自动制造一场新的上层谈话。

断线重连则不同。新的连接会有新的首次交换,因此有新的会话标识。应用可以自行恢复文件或任务,却不能因为用户名和主机名相同,就把两条 SSH 连接说成同一密码学会话。

用户签名把连接写进了请求

RFC 4252 没有让公钥认证只签用户名。publickey 方法的签名输入先放入会话标识,随后完整放入 SSH_MSG_USERAUTH_REQUEST 的关键字段:消息号、用户名、服务名、方法名、布尔值、公钥算法与公钥数据。

于是,从连接 A 截获的签名搬到连接 B 时,最前面的会话标识已经不同,验证自然失败。攻击者也不能悄悄改账户、服务或算法,因为这些字段同样属于被签内容。

这份证明回答的是一个窄问题:这把私钥的持有者,是否在这条连接里同意了这项具体认证请求。服务器还要另外判断公钥能否代表所声称的账户、是否需要第二种认证方法,以及服务政策是否允许继续。签名有效与认证完成不是同义词。

hostbased 方法沿用相同的会话绑定,同时加入客户端主机与其本地用户。主机私钥的持有证据同样不能取代主机名核验与登录授权。

登录成功没有预先批准所有通道

服务器发出 SSH_MSG_USERAUTH_SUCCESS 后,认证阶段结束,请求的服务开始运行。但连接层接下来可能提出许多此前尚不存在的问题:是否准许交互式 shell,是否开放文件子系统,是否转发某个端口,是否暴露认证代理,是否能到达某个目的地。

这些权力由服务器本地政策决定。有些决定在认证时根本无法做出,因为客户端尚未说明要打开什么通道。会话标识的作用是让上层证明指向正确的受保护语境,而不是把一次认证成功膨胀成所有未来行为的总许可。

审计也必须尊重这条边界。只保存“公钥登录成功”与会话标识,可以把认证事件关联到传输;没有通道请求与政策结果,就不能证明执行了哪条命令、开放了哪个转发或实际处理了什么数据。

算法老去,绑定规则没有随之漂移

2006 年文档里的算法不可能永远合适。RFC 8332 为服务器与客户端认证增加了 SHA-256、SHA-512 的 RSA 签名。已有 RSA 公钥材料可以保留 ssh-rsa 编码,同时由新算法名选择更强的签名过程。密钥格式、签名算法与签名对象被明确分开。

RFC 9142 后来更新了 SSH 密钥交换方法的实现建议,推动退出基于 SHA-1 的选择。协商空间能够演进,首次交换哈希作为会话锚点的结构却无需重写。

这不表示旧方法因“绑定正确”就变得安全。若最初信错主机密钥,或接受了不合适的算法,后续证明只会更准确地绑定到那个有问题的开端。连续性保存语境,不为语境背书。

五种常被混写的证据

主机名表示预期目的地;主机密钥是需要与该名称建立关系的密码学主体;交换哈希描述一轮协商;首个交换哈希标识一条连接;用户密钥为具体请求提供持有证明。本地授权政策则决定实际操作。

把它们全叫作“SSH 身份”,会抹去每一步是谁观察、谁判断、谁授权。RFC 能证明协议语义与算法演变,不能替具体部署证明主机密钥得到核验、rekey 按时发生、SHA-1 已消失,也不能证明某条命令真的执行。

SSH 的历史选择很克制:允许保护手段老化、轮换,却不让上层忘记自己的起点。留下来的哈希不是统治整条连接的权威,它只是后来证明可以准确引用的语境。