OpenSSH 8.9、OpenSSH9、OpenSSH9.1私钥转发登陆提示Permission denied (publickey,gssapi-keyex,gssapi-with-mic)

OpenSSH 8.9、OpenSSH9、OpenSSH9.1私钥转发登陆提示Permission denied (publickey,gssapi-keyex,gssapi-with-mic)
首先我说一下我目前的环境,只允许用key登陆,不允许用密码登陆,下面是sshd_config配置:

Password Authentication no
Pubkey Authentication Yes

有时候需要用scp在两台服务器之间传输文件,就用到了key转发。关于原理我也不太清楚,没升级之前一直是没问题的,我升级了OpenSSH9.1后,两台服务器都添加了我的公钥,我用xshell可以连上两台服务器,但是想用scp在两台服务器之间传输文件就遇到这个报错:
Permission denied (publickey,gssapi-keyex,gssapi-with-mic)
用ssh –v root@192.168.1.1 看到了下面的报错:
get_agent_identities: ssh_fetch_identitylist: communication with agent failed
用ssh-add –l也能看到我的私钥各种尝试无果,查看OpenSSH官方网站才看到,原来OpenSSH 8.9升级了代理限制,不允许key转发了。所以导致无法登陆,回退版本至OpenSSH8.8后一切正常。
下面是官方的说明:(我也没看懂啥意思,有能看懂并解决这个的兄弟麻烦给出个教程,然后踢我一下,我也看看……)
https://www.openssh.com/agent-restrict.html#limitations

下面是我翻译网页后保存下来的说明

SSH 代理限制

作者: Damien Miller djm@openssh.com
最后修改时间: 2022-01-10

TLDR

OpenSSH 8.9 将能够控制 ssh-agent中的密钥在本地和转发时的使用方式和位置(受某些 限制 )。

背景

OpenSSH SSH 协议实现包括ssh-agent 身份验证代理。该工具支持两种重叠用途:一种用于未包装 私钥的安全运行时存储,无需为每次使用输入密码,以及一种将对私钥的访问转发给远程主机,而 不暴露私钥本身的方法。

该代理是一个特意设计的简单程序,因为它持有私钥,我们将其视为TCB的一部分,因此希望尽量 减少其攻击面。它使用一个简单的、由客户端启动的协议,其中包含少量操作,包括添加或删除密 钥、检索已加载密钥的公共部分列表,以及最重要的是,使用私钥进行签名。与代理的大多数交互 都是通过ssh-add工具来添加、删除和列出密钥和ssh,它可以使用代理中保存的密钥来进行用户身份 验证,但也可以使用其他工具(如果它们使用协议)。

如上所述,可以将对代理的访问转发到远程主机。通常,这发生在 SSH 客户端和服务器安排允许远 程程序与本地代理建立连接并通过该连接交换消息时。转发代理看起来与本地代理实际上相同,因 为(直到现在)协议没有提供区分它们的方法。

不幸的是,由于代理持有敏感密钥,因此它是攻击者理想且经常利用的目标。一个典型的场景开始 于用户将他们的代理转发到由攻击者控制的主机。一旦发生这种情况,攻击者就可以充分利用代理 中保存的密钥,他们通常会使用这些密钥来验证到他们想要访问的主机的 SSH 连接。

虽然用户最好完全避免使用转发代理(例如使用 ProxyJump 指令),但代理协议本身几乎无法防 御此类攻击。可以使密钥在一段时间后自动过期或将密钥标记为每次使用都需要确认(通过弹出窗 口),但这些很少使用,而且确认在某种程度上很容易被钓鱼,例如,如果攻击者知道什么时候用 户很可能正在建立 SSH 连接——不幸的是,确认弹出窗口不能提供关于被认证的目标主机或请求 到达的转发路径的信息。需要用户存在确认的 FIDO 密钥提供了更多的防御,但也同样容易被钓 鱼。

什么会更好?
考虑什么是更好的控制集可以让我们确定更安全的代理协议的一些可能要求。 提高代理安全性的一个简单胜利是在上述两个用例之间提供更好的分离。将密钥添加到代理以供本
地使用不一定会使它在转发代理上可用。这将使用户将密钥存储在代理中,而不必担心它们可能被
恶意主机使用。因此,第一个要求是能够将密钥添加到仅供本地(即不转发)使用的代理。

相反,转发代理也很有用,但并非所有远程主机都同样值得信赖,并且用户经常连接到完全不同的 信任域中的主机(例如,笔记本电脑上的用户连接到测试、生产或个人环境)。一个好的解决方案 是允许将不同的密钥子集转发到不同的远程主机。

由于转发链有时涉及多个跃点,因此我们希望 逐个跃点应用密钥转发限制,每个额外的跃点只会从 可在目的地使用的密钥中删除密钥。已经麻烦地制作了一个可以根据转发路径推断密钥可用性的限 制系统,在确认对话框中显示路径信息也很好。例如,FIDO 密钥的通知可以说明目标主机和转发 请求的路径。

当然,这个练习的全部目的是让代理转发更安全。特别是,系统应以 密码方式保证密钥永远不会用 于对意外目的地的身份验证,并且转发的密钥只能通过允许的主机可见/可用。最后,当某些参与者 缺乏运行所需的协议功能时 ,系统应该会出现故障。

OpenSSH 中的代理限制

OpenSSH 8.9 将包含一组满足上述要求的实验性代理限制,但有一些警告(下面讨论)。这些是 围绕两个简单的代理协议扩展和对公钥身份验证协议的小修改构建的。

这些扩展允许用户将目标约束添加到他们添加到ssh-agent的密钥,并让ssh强制执行它们。例如,这 个命令:

$ ssh-add -h “perseus@cetus.example.org”
-h“scylla.example.org”
-h “scylla.example.org>medea@charybdis.example.org”
~/.ssh/id_ed25519

添加仅在以下情况下才能用于身份验证的密钥:

  1. 作为任何用户从原始主机到scylla.example.org 。
  2. 作为用户perseus从原始主机到cetus.example.org。
  3. 通过scylla.example.org以用户medea的身份托管charybdis.example.org。

尝试使用此密钥向其他主机进行身份验证将被代理拒绝,因为它们未明确列出,因为不允许通过 scylla.example.org向cetus.example.org进行身份验证的尝试 也是如此。同样,尝试以任何其他用户 的身份进行身份验证,然后通过perseus到cetus.example.org或medea到 charybdis.example.org将失败, 因为不允许目标用户。

更深层次的转发限制链是可能的,每个跃点都需要单独指定:

$ ssh-add -h “scylla.example.org”
-h “cetus.example.org”
-h “scylla.example.org>charybdis.example.org”
-h “cetus.example.org>charybdis.example.org”
-h “charybdis.example.org>hydra.example.org”
~/.ssh/id_ed25519

请注意,这组限制允许通过两条不同的路径到达hydra.example.org 的最终目的地:

在每一跳,只有被允许使用的密钥是可见的。例如,如果用户试图在 hydra.example.org上列出可用 密钥,则该密钥不会显示为可用。同样,尝试删除或调整受限密钥上的选项将在原始计算机以外的 任何地方被拒绝。

限制

需要协议扩展

最直接的实际考虑是,此功能需要在ssh-agent、ssh-add、ssh和sshd中为大多数参与主机进行协议扩 展。运行更新的ssh-agent、 ssh 和ssh-add的要求相当明显(旧版本根本不支持该功能),但运行更 新的 SSH 服务器的要求不太明显(原因在下面讨论)和更有可能成为部署的挑战。

允许的转发主机由 hostkey 标识

另一个实际限制是由于转发限制使用主机密钥来识别允许的主机。主机密钥是在 SSH 协议中识别主 机的主要方式,也是唯一可以通过代理探测的加密可验证方式。

添加具有目标约束的密钥时,ssh-add将使用本地known_hosts文件将命令行上给出的主机名映射到主 机密钥,然后再将它们传递给ssh-agent。这意味着用户列出的所有主机的所有密钥必须出现在正确 的位置(运行ssh-add的机器)和正确的时间(运行 ssh- add时)。

主机密钥并不总是最容易使用的东西。一个主机可能有多个不同类型的密钥,或者有多个名称—— 例如一个完全限定的域名、一个不合格的主机名或只是一个地址。

如果您计划使用这些新的代理控件,那么用户将需要对其known_hosts数据库保持良好的控制。 OpenSSH 提供了一些可能使这更容易的功能,包括 UpdateHostkey 扩展,允许客户端了解服务 器主机密钥的完整集合(最近已默认启用),以及 CanonicalizeHostname 选项,使客户端更容易 存储并在使用非限定名称时引用完全限定的主机名。

证书主机密钥的情况要简单得多。如果正在使用证书主机密钥,则运行ssh-add的主机只需要目标约 束中列出的主机的 CA 密钥,并且能够按名称匹配由这些 CA 密钥制作的证书。这是在组织设置中 使用主机证书的另一个很好的理由。

目的地比路径更值得信赖

目标约束由ssh-agent检查,使用从协作 ssh 传递的信息。如果代理被转发到攻击者控制的主机,那 么他们仍然能够窃取该主机上转发代理的使用权。

不太明显的是,他们还将能够将代理的使用转发给其他主机,例如,通过使用不与ssh-agent合作的 SSH 实现,或完全使用其他工具,例如 socat。请注意,攻击者在这里没有获得对密钥的任何新访 问权限,他们仍然被迫通过受感染的主机进行操作,并且他们的访问权限仍然仅限于仅允许通过预 期主机使用的密钥。

相关攻击涉及恶意跃点重播会话绑定消息(见下文)。他们之所以能够这样做,是因为ssh-agent无 法保证这些消息的新鲜度。这种攻击允许恶意跃点使转发路径看起来比实际更长。

然而,在所有情况下,由于签名和服务器主机密钥之间的绑定, 无法伪造最终目的地。因为绑定是 由本地客户端提供的,所以假设转发路径中第一跳的身份也是正确的也是合理的。

由于这些微妙之处,最好将密钥约束视为允许通过给定主机而不是来自特定主机使用密钥,并且更 一般地说,任何转发路径的强度取决于其最薄弱的链接。考虑密钥约束的另一种有用方法是,每个 密钥约束都代表对主机的密钥委托,主机只比委托稍微更值得信赖。

协议扩展假定特定的操作顺序

ssh-agent 中的限制检查对通过代理连接执行的操作做出了强有力的假设。这可能只与直接与代理协 议交互的工具的作者有关。

在OpenSSH中,从ssh客户端到agent的一个连接是为用户认证而建立的,在用户认证完成后关 闭。当与转发代理建立 SSH 会话时,在执行调用代理的操作(例如,列出密钥或向另一台主机进行 身份验证)时,会根据需要建立额外的代理连接。

代理协议扩展特意将ssh为身份验证建立的初始连接与为代理转发建立的连接区别对待。其他想要使 用这些扩展的 SSH 实现必须遵循这种模式。

限制仅适用于用户身份验证

ssh-agent中的 目标限制在很大程度上取决于代理能够解析正在签名的数据,以及具有与为给定密钥 列出的限制进行比较所需的所有信息的内容。SSH 用户身份验证请求具有满足这些要求的格式,但 代理协议的其他用途不太可能。

特别是,目前无法通过ssh-keygen、CA 操作等将目标限制密钥用于 SSH 签名。可能会放宽此限制
(见下文)。

这个怎么运作

目的地限制密钥通过三个相当简单的协议扩展实现:

一个新的代理协议密钥约束扩展,允许从ssh-add到ssh-agent的通信目的地限制。 一个新的代理协议会话绑定扩展,允许ssh通知ssh-agent密钥的使用位置。 在ssh和sshd之间使用的一种修改后的公钥身份验证方法,它将服务器主机密钥合并到签名数据 中。

这些协议扩展确保新的权限检查逻辑代理拥有所有必要的信息,以加密方式验证身份验证请求的预 期目的地和它所经过的路径。

可以通过 OpenSSH 源代码分发的 PROTOCOL 文件找到每个扩展的有线格式的详细规范。

限制密钥
协议扩展首先使用ssh-add工具 向ssh-agent添加目标约束密钥。 当请求添加一个具有一个或多个约束的密钥以用于/通过特定主机时,ssh-add将从本地known_hosts数
据库中查找主机的主机密钥,并将它们与SSH2_AGENTC_ADD_IDENTITY消息中的密钥一起编码。具体来
说,将对以下每跳约束中的一个或多个进行编码:

字节 SSH_AGENT_CONSTRAIN_EXTENSION (0xff)
字符串“restrict-destination-v00@openssh.com” 约束[]约束
字符串 [空] 来自主机名的字符串 keyspec[] 来自_keyspec
字符串关键字 布尔key_is_ca
字符串 to_username 字符串 to_hostname keyspec[] to_hostspec
字符串关键字 布尔key_is_ca

ssh-agent记录针对密钥的每个跃点约束,以供以后进行权限检查。约束中的主机名主要用于证书主 机密钥中的主机名检查(即当 key_is_ca 为真时)。from_hostname 和 from_keyspec 字段可能 为空以表示原始主机,但它们对于到/通过主机始终是必需的。

构建转发路径

ssh-agent 可见的路径,从源头通过转发主机到目标身份验证请求,是通过ssh发送会话绑定消息作为 代理连接建立后的第一条消息来建立的。在代理连接的生命周期中,此消息以加密方式将 SSH 连接 的会话标识符(如RFC4253 第 7.2 节中所述)与服务器的主机密钥链接起来。这允许代理在代理连 接和 SSH 连接之间建立可信链接。

消息格式为:

字节 SSH_AGENTC_EXTENSION (0x1b)
字符串 session-bind@openssh.com 字符串主机密钥
字符串会话标识符 字符串签名 布尔is_forwarding

其中签名字段是服务器使用其主机密钥对会话标识符的签名,如在初始客户端/服务器密钥交换的最 终SSH2_MSG_KEXDH_REPLY / SSH2_MSG_KEXECDH_REPLY消息中发送的那样。is_forwarding 标志指示此绑定是 用于转发 (true) 还是用于身份验证尝试 (false)。

当代理收到此消息时,它会使用包含的主机密钥验证签名并检查会话标识符之前是否未记录在此连 接上。如果这些检查通过,则主机密钥和会话 ID 将附加到连接的绑定列表中。

当通过深度转发路径请求代理连接时,扩展到原始主机之外,每个 SSH 客户端将在收到成功打开通 道的确认后立即发出绑定请求,然后再将通道传递到下一跳. 这确保绑定列表将以正确的顺序扩展, 并且只需要信任每个跃点的 SSH 客户端即可正确完成其工作。

验证身份验证尝试

为了确保代理拥有决定是否允许身份验证尝试所需的所有必要信息,公钥身份验证请求被扩展为还 包括服务器的主机密钥:

字节 SSH2_MSG_USERAUTH_REQUEST
字符串用户名 字符串“ssh 连接”
字符串“publickey-hostbound-v00@openssh.com” 布尔 has_signature
字符串包 字符串公钥
字符串服务器主机密钥
字符串签名 [仅当 has_signature 为真时]

除了添加服务器主机密钥字段外,此请求与RFC4252中描述的常用“公钥”身份验证请求相同。当 尝试进行身份验证时,签名是通过连接的会话标识符和整个 SSH2_MSG_USERAUTH_REQUEST数据包的串联 进行的(这与标准 SSH 协议相同)。

要使用代理发出身份验证请求,客户端将通过SSH2_AGENTC_SIGN_REQUEST 消息将要签名的数据传递给 代理。ssh-agent现在可以尝试解析待签名数据并提取会话标识符、服务器用户名,以及由于上述扩 展而提取的服务器主机密钥。

在这一点上,代理拥有它需要的所有信息来强烈识别身份验证请求的目的地,并将其与上一步建立 的绑定列表相关联。代理将确认签名请求已沿着允许的转发路径发出并在完成之前到达允许的目的 地。

在签名数据中包含主机密钥会将签名绑定到预期目的地,并防止攻击,其中可以访问一个允许目的 地的主机密钥的 MITM 为另一台主机签署会话绑定请求。

请注意,第一跳连接不需要此主机密钥绑定,即那些源自运行代理程序的主机的连接。这允许非传 递目标限制对不支持主机绑定签名扩展的服务器有用。

服务器使用SSH2_MSG_EXT_INFO机制 ( RFC8308 ) 使用以下通告向客户端发送对主机绑定签名的支持信 号:

字符串“publickey-hostbound@openssh.com” 字符串“0”(版本)

故障安全操作
当主机缺少必要的协议扩展时,此功能通常会安全地降级(尽管不是特别优雅)。 如果代理缺少目标约束支持,则尝试使用ssh-add添加受约束的密钥将失败,因为所有密钥约束都被
视为关键约束,即代理不支持一个将导致操作失败。

如上所述,第一跳不需要主机绑定签名支持,但如果代理在转发的连接上解析未绑定的身份验证请 求,则该操作将被拒绝。

协议不会如此优雅地降级的一种情况是,如果对ssh-agent的访问是由不参与会话绑定协议的工具从 源机器转发到工具支持会话绑定的主机。根据之前讨论的 限制 ,这对代理来说是完全不可见的,并 且可能会产生意外。这种情况有点人为,但如果在客户端机器上同时使用旧的 OpenSSH 或非 OpenSSH 实现并且它在代理转发中处于活动状态,则可能会发生。

下一步

这是 OpenSSH 中的一项新功能,可能会进一步发展。 将来可能会在密钥确认和 FIDO 触摸/PIN 请求对话框中显示更多路径信息。

目前没有通信,因为签名请求和其他操作被ssh-agent拒绝,除了默认不可见的调试日志。这使得故 障排除变得困难。

ssh-add 提供的用户界面可能并非对所有用途都是最佳的。特别是,用户可能希望在单个参数中指定 整个转发链。这是故意没有实现的,因为当前的逐跳规范强调了跳权限的委托方面,但可能值得重 新审视这一点。

ssh-agent 中累积的路径信息可用于比当前实现的更能表达和更细粒度地控制密钥可用性。例如,可 以使密钥在转发路径末尾的主机上可用,而不是在初始主机上可用。类似地,可以添加通过特定主 机的“通配符”密钥转发,也可以选择性地放宽对服务器支持主机绑定公钥身份验证的需求。然 而,这些伴随着额外的警告和 MITM 风险,需要仔细评估和解释。

最后,除了用于用户身份验证的请求之外,还可以有选择地允许签名请求。SSH 密钥用于越来越多 的签名操作,包括 git 提交和拉取请求。例如,可能允许转发的密钥仅用于 git 签名。但是,所有 信任都将放在转发路径上,因为没有类似于主机绑定签名提供的内在目的地绑定。

考虑的替代方案

独立的代理套接字

以前的代理限制设计让代理提供多个套接字,并让ssh-add能够指定这些套接字中的哪些可以使用密 钥。与 ssh 中的 IdentityAgent 和 ForwardAgent 指令相结合,这将提供使密钥仅可用于来自源 的特定主机的身份验证,并将不同的密钥子集转发到指定主机的能力。

然而,这种设计需要大量的手动配置才能实现这一点,并且不提供可以使用密钥的加密保证。

仅更改代理协议(即没有服务器端更改)

此协议的先前版本仅包括对代理协议的更改,不包括主机绑定的身份验证方法。这种较早的设计具 有不需要服务器更新的优点,但遭受了上述重签名攻击。

主机绑定身份验证和最小代理协议更改

该协议的另一个潜在变体包括主机绑定身份验证更改,但删除了会话绑定机制。这将允许代理在发 出身份验证请求时强烈确定身份验证请求的目的地,但不会使其看到发出请求的转发路径。由于提 供的控制太少,而且 MITM 太容易针对网络钓鱼请求,这种设计被废弃了。

逐跳签名

另一种替代设计在更大程度上将sshd包含在协议中,方法是让它使用主机密钥对收到的转发代理消 息进行签名。这具有为请求提供新签名的优势,并避免了上述路径扩展攻击。但是,它要求sshd解 释代理协议(目前它不需要),并且除非非常仔细地设计,否则有创建暴露的主机密钥签名 oracle 的风险。

通过名称识别主机

该协议使用主机密钥来识别主机。有人建议,通过对 SSH 协议的其他部分进行额外修改,可以改用 主机名。具体来说,SSH 服务器可以在密钥交换期间断言主机名,并且这些名称可以与主机密钥一 起记录在known_hosts中,而不是使用用户输入的目标主机名。然后代理限制可能会使用这些名称而 不是更麻烦的主机密钥。没有采用此选项,因为它是对 SSH 协议的相当大的修改,需要修改密钥交 换(或至少是新的扩展消息)和主机密钥存储。

常问问题

问:添加密钥后是否可以修改密钥的约束?答:不,密钥在代理中是不可变的。不过,您可以用新 路径替换密钥。

致谢

作者要感谢:

谷歌零项目的 Jann Horn,他以令人尴尬的速度在协议的早期版本中发现了重签名攻击, Google 信息安全工程团队的 Thai Duong 审查协议,以及
OpenSSH 项目的 Markus Friedl 对协议和实现进行了多轮审查。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值