我有一个 php ssl 客户端和一个 C++ Qt ssl 服务器,我需要对客户端而不是服务器进行身份验证。
原因是 C++ Qt ssl 服务器实际上在桌面应用程序上运行,出于安全原因我不想为桌面应用程序提供私钥,也因为服务器不需要 self 验证。
所以我为客户端提供了证书和私钥,而服务器只有对客户端进行身份验证的证书。
但是在上述情况下,我从服务器端收到 ssl 错误,由于缺少共享密码,握手失败。
如果我向服务器提供它自己的本地私钥和证书,则握手成功完成。
下面是一些设置 ssl 的 php 代码:
/* $local_cert_path is a file containing a complete certificate
* verification chain and the private key
*/
if (! is_file($local_cert_path))
{
throw new Exception(sprintf('cannot find certificate path: %s', $local_cert_path));
}
$this->ctx = stream_context_create();
stream_context_set_option($this->ctx, 'ssl', 'verify_peer', FALSE);
stream_context_set_option($this->ctx, 'ssl', 'allow_self_signed', TRUE);
stream_context_set_option($this->ctx, 'ssl', 'local_cert', $local_cert_path);
和 C++(Qt):
QList<QSslCertificate> certs = cacerts();
socket->setCaCertificates(certs); // loading the CA
// socket->setLocalCertificate(":/res/cert.pem", QSsl::Pem);
// socket->setPrivateKey(":/res/key.pem");
socket->setPeerVerifyMode(QSslSocket::VerifyPeer);
socket->setProtocol(QSsl::TlsV1);
如果我向服务器提供它自己的本地私钥和证书(取消上面两行的注释),那么握手就会成功。
最佳答案
验证 SSL/TLS 服务器的身份对于防止 MITM 攻击是必要的。即使您使用客户端证书身份验证(又名相互身份验证),客户端也需要检查服务器的身份(通常通过检查它是否信任其 X.509 证书以及它是否与证书中的预期服务器身份相匹配)。为此,需要为 TLS 服务器配置这样的证书(及其关联的私钥)。 如果没有这个,客户端实际上可以很好地使用客户端证书进行身份验证,只是它不知道它对什么进行身份验证(因此可能导致 MITM 攻击)。
也就是说,在您的情况下,TLS 服务器不必是 TCP 服务器。实际上,TLS 倾向于在 TCP 之上使用。在大多数情况下,TCP 客户端也是 TLS 客户端,一旦客户端建立了 TCP 连接,它也会通过它发送一个 TLS ClientHello
,开始它作为 TLS 客户端的角色。
您可以使 TCP 服务器充当 TLS 服务器,方法是让服务器启动 TLS 握手并发送 ClientHello
。事实上,TLS Glossary将客户端定义为:
The application entity that initiates a TLS connection to a server. This may or may not imply that the client initiated the underlying transport connection. The primary operational difference between the server and client is that the server is generally authenticated, while the client is only optionally authenticated.
我已经在 Java 中试过了,它运行良好。在 Java 中,哪个角色是客户端,哪个角色是服务器,只有在握手发生后才会确定。在此之前,您仍然可以使用 setUseClientMode 更改 SSLSocket
的角色。 ,尽管 SSLServerSocket
(从 SSLServerSocketFactory
获得)将处于服务器模式,但从普通 Socket
转换而来的 SSLSocket
(由服务器端的 accept
产生)可以用作客户端 TLS 套接字,反之亦然。
TLS 允许这样做,但我不知道您使用的框架是否可行。
将普通 TCP 套接字转换为 TLS 套接字通常是通过 STARTTLS
(available in SMTP, IMAP and LDAP, for example) 等机制升级套接字的协议(protocol)所做的。 .
您需要从“真实”客户端到“真实”服务器建立普通 TCP 连接,将 TCP 客户端套接字转换为 TLS 套接字并将其设置为服务器模式,将您的 TCP 服务器套接字转换为 TLS 套接字, 将其设置为客户端模式并发起握手。
关于php - 在 SSL 握手中,是否可以颠倒角色?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8234033/