SSH:重用公钥和已知的中间人

信息安全 密码学 验证 密钥管理 SSH 密钥生成
2021-08-12 09:43:47

通常,人们建议在任何地方都使用单个私钥-公钥对(如果我们不是在谈论泄露私钥的可能性):

  1. 最佳实践:“每个用户一个 ssh 密钥”或“每个主机多个 ssh 密钥”
  2. 重用私钥/公钥
  3. https://serverfault.com/questions/80478/ssh-do-you-use-one-private-public-key-pair-for-each-remote-machine-or-a-single/80483#80483

    当通过 SSH 使用客户端证书身份验证时,这似乎会导致漏洞。由于建议如此受欢迎,我怀疑下面的“算法”不起作用。但我只是不明白它到底有什么问题。

我已尽力使我的描述尽可能详细,以尽量减少可能的差异,所以,请原谅我的长度......

前提条件

  • PC1在其已知主机中同时具有(S1_id_rsa.pubS2_id_rsa.pub )指纹。
  • Server1不知何故知道PC1的帐户在Server2上的存在。
  • 键:
    • PC1:有P1_id_rsaS1_id_rsa.pubS2_id_rsa.pub
    • Server1,攻击者:有S1_id_rsaP1_id_rsa.pubS2_id_rsa.pub
    • Server2 : 有S2_id_rsa , P1_id_rsa.pub

算法

这有点像众所周知的中间人攻击,但有点不同。

  1. PC1向Server1发送“Hi”
  2. Server1向Server2发送“Hi”
  3. 服务器共享它的公钥

    1. Server2发送Server1 S2_id_rsa.pub
    2. Server1发送PC1 S1_id_rsa.pub(而不是S2_id_rsa.pub
    3. PC1接受S1_id_rsa.pub的指纹(众所周知)
  4. 使用Diffie-Hellman生成两个单独的共享秘密隧道

    1. “服务器 1--服务器 2”

      1. Server2生成 DH1.a,并将使用 S2_id_rsa 签名的DH1.A发送到Server1
      2. Server1生成DH1.b,将DH1.B发送给Server2
      3. 隧道建立
    2. “PC1--服务器 1”
      1. Server1生成 DH2.a,并将使用 S1_id_rsa 签名的DH1.A发送到PC1
      2. PC1生成DH2.b并将DH2.B发送给Server1
      3. 隧道建立。
  5. 客户端身份验证(Server2现在想确保他正在与PC1交谈)

    1. PC1P1_id_rsa.pub发送到Server1
    2. Server1P1_id_rsa.pub发送到Server2
    3. Server2生成挑战,只能使用P1_id_rsa解决并将其发送给Server1
    4. Server1只是通过隧道挑战PC1
    5. PC1解决挑战并将答案发送到Server1
    6. Server1隧道应答Server2
    7. 完毕。
  6. 完毕

PS我查看了维基百科上的公钥密码学中间人攻击,以及这个非常详细的答案(我对整个过程的看法主要基于它),但我还没有找到答案。 .

我找不到可读的“完整的 ssh 身份验证和加密过程假人”......

我已经在 Server Fault 上问过同样的问题,但建议在此处重新发布。

4个回答

通常,人们建议在任何地方都使用单个私钥-公钥对(如果我们不是在谈论泄露私钥的可能性)

请注意,SSH 连接涉及两个密钥对:

  • 一是识别服务器主机(服务器有私钥);
  • 如果使用公钥身份验证,则用于识别用户(客户端拥有私钥)。

您引用的建议是关于用户密钥的。每个用户拥有一个私钥是一种可行的模型,尽管我不特别推荐它(每个主机或站点拥有单独的密钥对的成本并不高)。另一方面,服务器密钥永远不会重复。它们是在安装 SSH 服务器时重新生成的。

关于这个主题,除了您在问题中引用的帖子之外,另请参阅SSH 的 authorized_keys 和 known_hosts 文件有什么区别?

在您描述的攻击中,您混淆了密钥的角色。这些是主机密钥,ssh_host_rsa而不是用户密钥。这与您描述的攻击的工作方式没有直接关系,但可能是您困惑的一部分。

关键点在步骤 3.3:

PC1 接受 S1_id_rsa.pub 的指纹(众所周知)

有两种情况。

  • known_hosts如果 PC1 之前已经连接到 S2,那么 PC1(或者更准确地说是 PC1 上用户的帐户)已经在其文件中记住了 S2 的主机公钥。因此,如果 S1 发送 S2 的主机密钥,PC1 上的 SSH 客户端将检测到声称的主机密钥与记录的主机密钥不匹配,并以一条可怕的消息中止连接:

    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    @    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)!
    It is also possible that the RSA host key has just been changed.
    

    因此,在这种情况下攻击是不可能的(除非用户特意绕过检查——OpenSSH 故意让这变得困难)。

  • 如果 PC1 从未连接到 S2,那么 PC1 将愉快地接受 S1 现在告诉它是 S2 的密钥的任何内容。由于 PC1 事先不知道名称 S2 和加密身份之间的任何关联,也没有任何方式联系知道这种关联的可信第三方(即公钥基础设施),因此无法阻止这种人为中间攻击。

最后,我想我明白了。

首先 - 我在我的描述中混合了 ssh v1 和 ssh v2 协议。质询-响应授权来自 ssh v1。

在 ssh v2 中,客户端只需使用其私钥签署特定包,服务器使用存储的公钥对其进行检查。这个包在 rfc 中有描述,这里

To perform actual authentication, the client MAY then send a
signature generated using the private key.  The client MAY send the
signature directly without first verifying whether the key is
acceptable.  The signature is sent using the following packet:

  byte      SSH_MSG_USERAUTH_REQUEST
  string    user name
  string    service name
  string    "publickey"
  boolean   TRUE
  string    public key algorithm name
  string    public key to be used for authentication
  string    signature

The value of 'signature' is a signature by the corresponding private
key over the following data, in the following order:

  string    session identifier
  byte      SSH_MSG_USERAUTH_REQUEST
  string    user name
  string    service name
  string    "publickey"
  boolean   TRUE
  string    public key algorithm name
  string    public key to be used for authentication

因此,签名包包含“会话标识符”,其计算如下

  H = hash(V_C || V_S || I_C || I_S || K_S || e || f || K)
  <…..>
  mpint     K, the shared secret  

也就是说,签名确实依赖于共享秘密,并且P1 <-> S1S1 <-> S2隧道的共享秘密是不同的。

问题是由于使用了服务器 1 的证书,客户端会知道他们正在与服务器 1 交谈。如果 server1 具有表明它们是 server2 的有效证书,那么客户端将不知道他们之前是否没有连接到 server2。然而,大多数 SSH 客户端会跟踪它们连接到给定服务器的证书的指纹。当客户端连接并最终连接到服务器 1 时,即使证书已签名,用户也可能会收到指纹已更改的警告。

至于与 S1 的已知连接试图声称是 s2,如果 s2 准确地知道 p1 的私钥,那么如果 01 想通过 s1 与 s2 交谈,那么它应该为 s2 加密,然后 s2 将为 p1 加密。当 p1 没有从 s2 获得密钥交换时,它会知道存在问题,因为 s1 无法将 p1 作为 s2 签署交换。

实际上,这是一个已知漏洞,信任列表中的证书已被破解,以及为什么需要吊销列表。

要使这种攻击起作用,需要有 2 个漏洞:

  1. PC1 必须认为它正在与 server2 通信,而实际上它正在与 server1 通信。
  2. PC1 必须具有S1_id_rsa.pub可信证书,并且它指向 server2 的地址(否则 PC1 将知道它正在与 server1 而不是在步骤#4.3 中的 server2 通信)。

#1 可能发生在不受信任的网络上,而 #2 只能发生在先前发生的违规行为允许 server1 将自己插入为受信任方时。