ssh 公钥认证是如何工作的?

信息安全 验证 SSH
2021-08-31 13:10:14

我的基本理解是这样的:

  • (连接到的)服务器sshd使用公钥加密一些消息
  • 客户端的sshssh-agent解密它并发回一些东西(消息的校验和?它的签名?)
  • 服务器sshd验证这与验证用户的消息是否一致

但细节是什么?什么是“一些消息”,ssh(-agent)发回什么?一遍又一遍地使用相同的原始消息执行此操作总是会产生相同的通信吗?

如果ssh-agent使用此身份验证过程,是否可以通过 bash 工具重播例如,ssh-agent提供的公钥可以通过 获取ssh-add -L,那么剩下的过程呢?还是需要手动连接到$SSH_AUTH_SOCKunix 套接字和一些低级通信?


相关:Thomas 的 Server-Bob 对话在这里,尽管这表明客户端只是签署一些随机数据,然后将针对服务器用户的所有公钥进行检查authenticated_keys另一方面,此说明声称消息已加密为先前确定的用户的公钥(不是用于 ssh 加密的公钥),并且客户端输出的校验和也取决于一些随机会话 ID。哪一个是正确的?还是两者都只讲述了更复杂的故事的一部分?

2个回答

简单来说:

  • SSHv1:服务器使用存储在 中的公钥加密消息authorized_keys,客户端必须解密并返回它的校验和(由会话 ID 修改)
  • SSHv2:客户端签署消息(取决于会话 ID)并传输签名和消息(不包括会话 ID),包括使用的公钥。然后,服务器预先添加会话 ID 并验证签名(假设公钥实际上在 中authorized_keys

文档PROTOCOL.agent总结了这一点:

协议 1 和协议 2 密钥由于不同的加密用法而分开:协议 1 RSA 私钥用于解密使用相应公钥加密的挑战,而协议 2 RSA 私钥用于使用私钥对挑战进行签名使用相应的公钥进行验证。使用相同的密钥进行签名和加密被认为是不合理的做法。

这是RFC 4252中的 SSHv2 相关部分

为了执行实际的身份验证,客户端可以发送
使用私钥生成的签名。客户端可以直接发送
签名而无需首先验证密钥是否
可接受。使用以下数据包发送签名:

  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

'signature' 的值是对应私钥对以下数据的签名,顺序如下:

  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

当服务器接收到这个消息时,它必须检查
提供的密钥是否可以用于身份验证,如果是,它必须
检查签名是否正确。

认证的细节取决于协议版本和密钥类型。在所有情况下,总是存在挑战,具有一些随机性以避免重放攻击。当用户密钥是 DSA 类型时,必然涉及真正的数字签名,因为 DSA 是一种仅签名算法。您链接到的文章显示了一些假设用户密钥可以进行非对称加密的内容;我猜这是 SSHv1 所做的事情(在 SSHv1 中,所有密钥都是 RSA,而 RSA 可以进行非对称加密)。对于当前 (SSHv2) 协议,基于公钥的客户端身份验证在RFC 4252第 7 节中指定。

.ssh/authorized_keys核心概念保持不变:客户端通过执行需要知道该密钥的操作来证明其对私钥的控制,但是可以使用位于服务器上的公钥完成“反向”操作.