我正在尝试使用SslStream
. 但是我的服务器证书是自签名的。
客户端拥有服务器证书的公共部分的副本,假定通过防篡改(但不是防监听)通道传输。
我可以安全地使用它来对服务器进行身份验证吗?为此,我应该在客户端SslStream
或它的服务器中放入什么RemoteCertificateValidationCallback
?到目前为止,由于缺乏信任,我所有使用验证的尝试都失败了,我的回调现在所做的是比较名称和指纹。
如果可以接受,如何让客户“信任”其公共证书副本以进行验证?
我正在尝试使用SslStream
. 但是我的服务器证书是自签名的。
客户端拥有服务器证书的公共部分的副本,假定通过防篡改(但不是防监听)通道传输。
我可以安全地使用它来对服务器进行身份验证吗?为此,我应该在客户端SslStream
或它的服务器中放入什么RemoteCertificateValidationCallback
?到目前为止,由于缺乏信任,我所有使用验证的尝试都失败了,我的回调现在所做的是比较名称和指纹。
如果可以接受,如何让客户“信任”其公共证书副本以进行验证?
第一个解决方案很简单,但仍然存在漏洞。那就是检查密钥指纹是否匹配。但是,任何中间人都可以建立中间连接并创建自己的密钥交换,然后制作你的以匹配他的,在那时共享加密密钥。
根本问题是您没有适当的基础设施。这并不是说您使用的是自签名证书本身,而是您使用的是来自同一个“CA”的自签名证书。您需要为您的证书颁发机构(您自己)创建一个根证书,然后您需要从该密钥批准 CSR 以供您的软件使用。这意味着所有远程机器都需要信任您的根证书并将其作为证书颁发机构安装在他们的机器上。通过这样做,您可以避免应用程序使用的证书在中途受到损害或类似的问题。但这仅适用于您可以以有保证的防篡改方式将该根 CA 证书提供给用户。
解决您的问题的一个不同但更激进的解决方案是基本上放弃 SSL 或对该证书的有效性进行带外身份验证。客户端可以验证证书,因为服务器能够解密客户端的消息并做出适当的响应。像这样的质询响应方案可以数学/密码证明服务器具有预期的证书,或者至少该方具有相应的私钥:
Client generates a 256 bit random nonce (RNGCryptoServiceProvider), K_C
Server generates a 256 bit random nonce, K_S
Client encrypts K_C with server's assumed public key, now K_B
Server digitally signs K_S, K_A
Server transmits K_A to client
Client transmits K_B to server
Server decrypts K_B, now N_S
Client verifies K_A using server's assumed public key, if invalid disconnect
Client computes K_A XOR K_C, now Z_C
Server computes N_S XOR K_A, now Z_S
Server transmits Z_S to client
Client verifies Z_S matches Z_C
Client transmits Z_C to server, encrypted using the server's public key
Server decrypts Z_C and verifies that it matches Z_S
如果一切顺利,挑战就完成了,您可以保证服务器拥有您拥有的公钥的私钥。您也不能只是快捷方式并将服务器公钥的数字签名副本传输给客户端,因为任何中间人都可以在任一侧创建两个会话此方案可防止中间人建立两个会话,因为客户端已经拥有公钥,并通过使用服务器的公钥加密他们的随机数来直接挑战有效性。对此最好的攻击是中间观察者,如果不利用所使用的非对称算法的弱点,就无法篡改数据。
此方案的另一个好处是,此时您可以完全避免 SSL,因为您已经独立进行了身份验证。现在,您实际上可以利用Z_S == Z_C
自己的优势并考虑Z_S
或Z_C
(它们相同)作为您商定的对称密钥以进行进一步的通信。
不久前,我写了一篇关于类似方案的论文,并在几个地方发表了。您可能可以通过“具有挑战性的身份验证协议(CAAP)”的名称找到它,日期为 2007 年或以我的名义在 2010 年修订。有代码示例。