1

我正在尝试在将暴露给公共互联网的服务器上设置 TCP 流(非 HTTP),但只有“选择的”客户端应该能够连接到。据我了解,这通常由证书固定处理,但我不熟悉如何完成的所有细节。

  1. 为服务器生成 SSL 证书。这很容易。
  2. 设置服务器。当客户端连接时,让它调用如下内容:
private SslStream GetSslStream(TcpClient client, string certificateFile)
{
    var c = X509Certificate.CreateFromCertFile(certificateFile);
    var cert = new X509Certificate2(c);
    if (!cert.Verify()) {
        throw new Exception("Certificate failed verification");
    }
    var stream = new SslStream(client.GetStream(), false, VerifyClientCert);
    stream.AuthenticateAsServer(cert, true, true);
    return stream;
}
  1. 客户端证书从何而来?它是服务器 SSL 证书的副本吗?它是必须以某种方式从服务器的证书派生的单独证书吗?它是一个完全不同的证书吗?
  2. VerifyClientCert确保它是正确证书的方法是什么?只是对照预期值Verify()检查一下Thumbprint,还是还有更多需要发生的事情?
  3. 每个客户都应该获得相同客户证书的副本吗?
4

1 回答 1

0

证书固定是一个不同的概念。服务器使用 SSL 证书时,通常是由某个证书颁发机构颁发的。该机构的证书又可以由另一个证书机构颁发,形成一个链。当客户端验证服务器证书时,它会检查该证书颁发机构是否被此特定客户端“信任”。“受信任”反过来意味着上述链中的某些证书​​受此客户端信任。例如,Windows 和 Linux 操作系统都带有一组默认受信任的证书权限。如果服务器证书在其链中具有其中一些权限 - 那么它也是受信任的。

证书固定意味着您作为客户端,对服务器证书施加的限制比上述限制更多。例如,你可能会说对于这个域\端点,我只信任这个特定的证书(带有这个特定的摘要),我根本不关心信任链。或者对于这个端点,我只信任这个特定的证书颁发机构。这是证书固定。您可以将它用于您的服务器,但它有它的缺点,我不会在这里描述。

现在回到你的问题。您所描述的称为客户端证书身份验证。在 SSL 握手中,不仅服务器可以提供证书供客户端验证。服务器也可能要求客户端发送他自己的证书,以验证该客户端。这个证书当然与服务器的证书完全不同。

每个客户必须有不同的证书。通常使用以下两个选项之一:

  1. 您(服务器所有者)创建自己的证书颁发机构(例如使用几个简单的 openssl 命令),然后您从该颁发机构为每个客户端颁发单独的证书。然后,您将这些证书(每个客户端一个),包括私钥,发送给它们各自的客户端。之后,您可以丢弃(删除)这些证书,因为您将不再需要它们。验证客户端证书时 - 只需检查它是否由您的证书颁发机构颁发。

  2. 或者为每个客户端颁发单独的证书,并且您存储这些证书的指纹(摘要\哈希),每个客户端一个。然后在验证期间确保指纹具有给定客户端的预期值。好处是您可以要求客户端生成此类证书并向您(服务器所有者)发送指纹。然后,您永远不会拥有该证书的私钥(与您自己的证书颁发机构的方法不同,您自己生成证书并在某一时刻拥有其私钥)。

于 2021-10-16T18:53:42.937 回答