摘要
- RFC 9987 标准化了 SSH agent 的请求—响应协议。agent 保存私钥,并可列出、装载、移除、锁定密钥或执行签名;基础协议本身没有认证和传输保护,能够接触端点通常就意味着能够请求私钥操作。
- Agent forwarding 不把私钥材料发送给远端主机,而是把调用本地 agent 的通路延伸过去。RFC 将其称为传递信任:远端可能偷不到密钥,却偷到一段时间内的使用能力。
- 生存期、逐次确认和扩展约束能够缩小能力,但目标服务器仍要独立判断公钥是否可用于指定账户、签名是否有效、是否需要更多因子,以及认证后允许哪些通道和操作。
审计报告里常见一句令人安心的话:“没有发现私钥外泄。”这句话回答的是材料保管问题。它说明攻击者没有拿到能够带走、离线保存并在将来重复使用的私钥副本。
它没有回答第二个问题:在暴露窗口内,攻击者能否让合法持钥者替自己完成运算?
设想一名工程师在笔记本上解锁密钥,通过 SSH 登录堡垒机,并启用 agent forwarding。堡垒机上的 socket 看起来像本地服务,实际消息沿 SSH 通道返回笔记本的 agent。一个被攻陷的堡垒机进程无法读取私钥种子或素数,却可能提交签名请求。若另一台服务器允许对应公钥登录某个账户,它就可能接受这次新签名。
私钥仍在原位。可执行的使用权已经越界。
被封存的材料与可调用的函数
RFC 9987 于 2026 年 5 月作为 Proposed Standard 发布。它把长期由实现使用的 agent 接口整理成共同协议。客户端驱动全部交互;agent 不主动发消息,按顺序回复。客户端能够查询身份、加入或移除密钥、锁定或解锁 agent,并请求私钥签名。
这种拆分有真实价值。SSH 客户端不必把解密后的私钥长期放在自己的内存里;专门的 agent 可以缩小攻击面,限制崩溃转储或调试,并把硬件令牌放在隔离进程中。用户也不必为每次连接重新输入口令。
但隔离改变的是风险形态,不是把风险消灭。RFC 明确指出,agent 协议没有内置认证,也没有内置传输安全。Unix 系统通常依靠文件系统 socket 权限和对端进程身份;Windows 通常依靠 named pipe 的安全描述符。SSH_AUTH_SOCK 常用来告诉客户端端点位置。
因此,socket 权限不是外围配置,而是调用权边界。谁能连接,谁通常就能请求私钥操作。硬件“不可导出”可以很好地降低材料被复制的风险,却不能自动回答谁能在线调用硬件。
签名请求的结构进一步说明了这一点。客户端提交公钥 blob、待签数据和算法标志。agent 成功返回签名,证明它在当前状态下接受了这次密码学操作。它不证明请求进程拥有组织授权,不证明数据对应批准的目标,不证明服务器接受,也不证明命令执行。
约束是会变化的运行状态
RFC 定义了生存期约束。密钥装载后经过指定秒数,agent 将其删除。这能关闭未来请求窗口,但不会撤销已经产生的签名,不会主动关闭目标服务器已经接受的会话,也不会回滚已经发生的动作。
逐次确认约束要求每个私钥操作得到显式确认。它可能是一道很强的门,也可能只是一种心理安慰。RFC 没有规定对话框必须显示目标主机、账户、会话或待签内容,也没有规定人如何理解“允许”。如果提示缺少上下文,或者短时间内连续出现,确认容易变成条件反射。
因此,证据不能只有布尔字段 confirm=true。它应记录实现实际展示了什么、由谁确认、对应哪一次签名请求。只有这样,“有人点击同意”才可能上升为“有人对明确场景作出知情决定”。
扩展约束采用了值得肯定的失败方式。agent 无法安全跳过一个未知约束,因此必须终止解析、拒绝加入密钥,而不是忽略限制继续运行。这个规则把不兼容变成明确拒绝,保护了用户的限制意图。不过,客户端与 agent 必须共同支持同一扩展;真正执行仍需测试证明。
约束还可能被重新装载改变。若相同密钥已存在,后续加入请求应以新约束替换旧约束,或者 agent 可以拒绝重复加入。早晨看到的一把“短时且需确认”的密钥,可能在工具重载后变成无约束密钥。应审计每次状态转换后的有效约束,而不是只保存最初配置。
锁定 agent 会暂停敏感操作,直到正确口令解锁。它是本地状态变化,不会追溯撤销远端结果。把“agent 已锁定”当成所有影响终止,是把一个节点的事实误写成全链路事实。
转发重画了信任图
Agent forwarding 通过 SSH connection protocol 把远端访问带回客户端侧 agent。远端获得的是协议消息通路,不是私钥副本。也正因为如此,它很容易在资产清单中隐身:清单仍显示密钥只在一台设备上,实际调用图却多出堡垒机及其进程。
RFC 9987 直接把转发称为传递信任关系,并建议实现不要默认开启,用户也不应转发到不完全信任的主机。如果没有对转发连接增加密钥可见性和使用控制,用户面对的是全有或全无的选择。
“完全信任”不只是相信堡垒机的主机密钥。它还意味着信任本地特权进程、管理员、插件、部署链、共存工作负载以及检测能力。一台为了集中入口而设的堡垒机,可能同时集中多把远端密钥的可调用能力。
归因也不是拓扑自动赠送的。一个 SSH transport 可以承载多个 session,多个 session 可以并发请求同一个客户端 agent。agent-connect 请求没有字段指出它来自哪个 session channel。客户端在自身授权策略下,可以在没有先前 session 请求时接受 agent 连接,也可以在发起转发的 session 关闭后继续接受。
这些行为可以服务合法架构,却意味着不能凭“当时有一个 shell”就断定“这个 shell 请求了这次签名”。需要关联外层连接、转发请求、agent channel、密钥指纹、约束决定、签名响应和目标认证记录。
Agent 签名不是服务器判决
SSH 公钥认证在另一端设置了重要边界。RFC 4252 要求签名覆盖 session identifier 以及精确认证请求中的用户名、服务、方法、算法和公钥。目标服务器还要独立检查这把钥匙是否允许认证该用户,以及签名是否正确;它也可以要求更多认证方法。
这说明 agent 返回的签名不是可以任意重放的通用密码。它绑定具体会话和请求。但如果攻击者仍然拥有在线 agent 通路,就能为另一个正确构造的会话请求一枚新签名。单次签名防重放,不等于在线签名能力不可滥用。
至少要分开六个事实:密钥已装载;进程能到达端点;agent 按当前约束同意签名;签名绑定正确上下文;服务器接受公钥与签名;认证后的通道获准产生效果。任何一层的绿色状态都不能替下一层说话。
算法能力同样分散。agent 可能支持 RSA、Ed25519 或其他类型;客户端可以通过标志请求 RSA/SHA-2;服务器可能接受或拒绝;组织策略还可能更窄。IANA 注册表协调名称和值,并不证明某个真实系统启用、合规或推荐它们。
从材料审计升级为能力审计
在源端,应保留 agent 身份、端点权限和对端身份、密钥指纹、装载时间、有效约束、锁定状态与移除时间。若使用硬件令牌,还要记录提供程序模块及其隔离,因为加载共享库本身可能引入代码执行面。
在转发边界,应记录外层 SSH 连接、主机信任决定、转发请求、每条 agent channel 的建立与关闭,以及 session 关闭后仍存活的连接。还要区分显式请求、配置继承和机会式兼容行为。
在私钥操作处,记录时间、密钥、算法、待签上下文的安全指纹、约束判定和确认结果。日志无需泄露完整敏感内容,但必须足够把操作与目标认证关联起来。
在目标服务器,记录账户、授权公钥、签名验证、额外因子、来源路径、开启的 channel 和服务器侧限制。随后观察命令、子系统、端口转发或文件操作是被允许还是被拒绝。
最后要证明终止:移除密钥、关闭 agent 和转发 channel、在必要时撤销目标授权,并实际观察新尝试失败。只删除本地密钥,不能证明已经建立的远端会话自动消失。
这才是运行代码的证据链。它不否定“私钥未外泄”,而是把这句话放回它真正能够证明的范围。
会员简报
档案背景详情
使用相应会员等级登录,即可解锁完整简报与来源注释。
仅限 Strategic Circle
Strategic Circle
所有读者均可浏览。加入并登录后可解锁档案简报。
加入 Strategic Circle仅限 Leadership Alliance
Leadership Alliance
符合条件的 IP 资产所有者和管理层可登录查看 Leadership Alliance 简报。
加入 Leadership Alliance
