SSH 客户端如何确保 SSH 服务器承载私钥,也就是客户端的“known_hosts”文件中的一对公钥?

信息安全 验证 SSH 挑战-反应
2021-08-19 17:14:17

SSH 客户端显然以某种方式对 SSH 服务器进行身份验证。因为当服务器的密钥发生变化时,SSH 客户端软件会大声警告我们服务器的密钥被更改,这可能是中间人攻击。

但是,客户端是否使用质询进行此身份验证?也就是说,SSH 客户端是否使用服务器的公钥加密了一段随机生成的数据,并期望服务器能够使用其私钥对其进行解密并将解密后的数据发回,以便对服务器进行身份验证?

4个回答

安全外壳 (SSH) 传输层协议 (RFC 4253)描述了如何完成服务器身份验证。根据第 7 节,存在隐式和显式服务器身份验证。隐式身份验证需要客户端之间的共享机密。显式认证意味着“密钥交换消息包括签名或服务器真实性的其他证明”这是一种通常使用的服务器身份验证,即服务器有一个密钥对,客户端知道公钥,并且它想要验证连接的目标是否知道匹配的私钥。

第 8 节描述了如何在 Diffie-Hellman 密钥交换中包含显式身份验证。本质上,服务器使用服务器私钥对来自客户端的一些数据进行签名,以证明密钥的所有权,并且客户端使用已知的公钥验证此签名。这些客户端提供的数据包括随机数据,因此不可能重放旧签名。有关更深入的详细信息,请参阅RFC 本身

我不认为此检查是 SSH 客户端的身份验证,您所指的听起来像是 SSH 客户端中服务器主机密钥的缓存。这确实用于识别服务器,但它不是身份验证

SSH 有两种身份验证方案(我知道),在这两种情况下,验证的是客户端,而不是服务器:

1)(默认)简单密码认证,服务器向客户端询问密码。在这种情况下,客户没有检查。

2) 使用 SSH 密钥 - 这涉及在客户端计算机上生成私钥并将相应的公钥导入服务器。在这种情况下,与您所描述的情况类似,但客户端使用自己的私钥来加密服务器的消息。然后,服务器将根据客户端的公钥检查此加密消息。如果私钥保持安全,它被视为比简单密码更安全且更易于管理

这是 Digital Ocean 对 SSH 密钥身份验证过程的一个很好的细分

DigitalOcean 也对这个话题感到沮丧,我提出了这个答案。参考是RFC4253的第 8 节,在 Diffie-Hellman 密钥交换期间声称:

首先,客户端发送以下内容:

  byte      SSH_MSG_KEXDH_INIT
  mpint     e

然后服务器响应以下内容:

  byte      SSH_MSG_KEXDH_REPLY
  string    server public host key and certificates (K_S)
  mpint     f
  string    signature of H

基本上,在Diffie-Hellman 密钥交换/生成期间,客户端从其密钥“x”创建密钥“e”;服务器将对“y”中的“f”执行相同的操作。使用“x”和“f”(客户端)或“y”和“e”(服务器),在两侧计算加密密钥“K”(我让您看看 Diffie-Hellman 魔术)。

然后诀窍就来了:)双方都进行了一次大计算:“H”。这是一个长字符串的哈希,包括许多东西,如 e、f、服务器名称“V_S”、客户端名称“V_C”、以前的消息内容(来自客户端/服务器的“SSH_MSG_KEXINIT”=“I_C”/“I_S”) ,公共服务器密钥“K_S”,最后但并非最不重要的,秘密密钥 K:

H = 哈希(V_C || V_S || I_C || I_S || K_S || e || f || K)

H 没有明确提供给客户端,因为它知道所有这些信息,因此也可以计算它;而是服务器提供 H 的签名,用服务器私钥计算。然后,客户端可以检查这个签名,这要归功于它自己计算的 H 和公钥 K_S 来验证服务器。

恕我直言,重点是混合 - 至少 - K(秘密)和签名:没有 MitM 可以伪装这样的消息!

这似乎是您问题的相关答案:验证公共服务器的 SSH 指纹

简而言之,SSH 服务器有一个公钥和私钥,用于从 SSH 客户端建立连接。服务器将向客户端提供其公钥的副本,并将其呈现给用户进行验证。然后,用户负责与服务器管理员验证该密钥,然后接受该密钥。

一旦被接受,用户只会在密钥更改时再次看到它。当密钥发生变化时,可能是管理员在服务器上进行的重新密钥或通过 MITM 式攻击;您需要与管理员重新验证密钥以查看哪个是哪个。

正如我相信您试图提出的那样,没有“挑战”,因为这正是公钥密码学的工作原理。

编辑: SSH 服务器将在安装期间通过使用应用程序自动生成它的主机密钥ssh-keygen这通常会创建一个 RSA、DSA、ecdsa 或 ed25519 密钥,或其中的一些变体(取决于配置)。

连接到服务器的客户端将用于ssh-keyscan检查服务器的指纹并将其作为用户呈现给您以进行验证。当您接受该密钥时,它会将其写入~/.ssh/known_hosts文件以记住它。每次您的 ssh 客户端将其连接到该服务器时,它都会读取指纹,在known_hosts文件中检查它并确保它没有更改。如果是这样,您(用户)会收到一条警告,提示您密钥已更改并且连接已停止。您必须手动删除或更改密钥才能再次连接。

$ ssh-keyscan some.remote.server
some.remote.server ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA8BPNr+Q8cQfU95jfJKIfAH+z0+q03QDeFH1ndeTC3Zf0EDjZOg1OXs+Xiwjgrkq+vcNIA5DPaux3aStrcSa5o1AjgBNKN4rMyaLMW1c5LUnSic2oE7YTGvO1AHL55+Z4rCiEbDHeK2LXwhZifNvqkxf44pKrIe8kCvt89dkRsCria4n5EedGazKxO0mvbHM9JSpg03CiD4B+/afOrZqCJrf5dYcDCmeiBPSn9vjiZzAl2NYj05GVSqoe8KeFQV9n4c4LtWfzSDshvLlypuSfylzhL3euWG6JP8G6HnBohSiSQFk/Y0VFX/4wYshKjN3px0ugYUrucXXv8Sznv6n1Dw==

如果您要known_hosts在我的系统上打开该文件,您会在其中看到这个确切的条目。

编辑2:

阅读评论,您似乎被困在这个指纹位上。指纹是公钥密码学的公共部分。您真的应该阅读更多有关此内容的信息,因为我之前链接过以完全理解此概念。在公钥加密中,私钥和公钥是同时在数学上创建的。这个密钥对拥有一个特殊的能力,任何被私钥加密的东西只能公钥解密,任何被公钥加密的东西只能被私钥解密。这是非对称密码,而不是对称加密(使用一个密钥进行加密/解密)。

您还必须了解签名的工作原理以了解公钥加密的使用。如果我用纯文本写了一条消息并发送给你,你不知道我发送了它。相反,如果我写一条纯文本消息,并在底部添加一个加密的 blob,其中包含消息的哈希并使用我的私钥加密,那么我的公钥可用于解密 blob,原始纯文本消息可以被散列并与我包含在加密 blob 中的散列进行比较。

同样的概念也适用于 SSH。由于只有服务器上使用的私钥能够与您的客户端拥有的公钥一起使用,您可以从数学上证明它们是同一台机器。正如我在评论中提到的,几乎不可能生成两个完全匹配的私钥,从而提供重复的指纹。如果您可以生成与另一台服务器的私钥完全相同的私钥,那么是的,您将拥有与其他服务器相同的指纹——今天认为这是不可能的。