SSL证书,不通过thrift进行身份验证,但可以通过浏览器进行验证

时间:2012-06-09 21:35:18

标签: c++ ssl openssl thrift

这是我生成SSL证书,密钥等的方式:

openssl genrsa -out server.key 1024
openssl rsa -in server.key -out new_key.pem
openssl req -new -key server.key -out server.csr
openssl x509 -req -days 10000 -in server.csr -signkey new_key.pem -out server.crt

这有效,我可以看到chrome中的输出,虽然我得到一个警告,我将首先得到病毒。

openssl s_server -cert server.crt -www -key new_key.pem

这是服务器的一个片段。老实说,虽然我有个好主意,但我不确定每条线路到底在做什么:

socketFactory->server(true); // this is the server
socketFactory->authenticate(false); // no auth?
socketFactory->loadCertificate("server.crt"); 
socketFactory->loadPrivateKey("new_key.pem");

客户端:

socketFactory->loadTrustedCertificates("server.crt");
socketFactory->authenticate(true); //auth? wierd, right? This guy does this:[1]

[1] http://permalink.gmane.org/gmane.comp.lib.thrift.user/1651

如果我在客户端注释掉loadTrustedCertificates,那么我会收到SSL未经验证的证书例外。 留下该行,我得到一个auth失败异常。

以下是两个更长的代码片段,它们将上述片段放在更好的视角中 服务器:

shared_ptr<SkullduggeryHandler> handler(new SkullduggeryHandler());
shared_ptr<TBufferedTransportFactory> transportFactory =
        shared_ptr<TBufferedTransportFactory>(new TBufferedTransportFactory());
shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
shared_ptr<TProcessor> processor(new SkullduggeryProcessor(handler));
shared_ptr<TSSLSocketFactory> socketFactory = 
      shared_ptr<TSSLSocketFactory>(new TSSLSocketFactory());
socketFactory->server(true);
socketFactory->authenticate(false);
socketFactory->loadCertificate("server.crt");
socketFactory->loadPrivateKey("new_key.pem");
shared_ptr<TSSLServerSocket> socket(new TSSLServerSocket(port, socketFactory));
TThreadedServer server(processor,
                               socket,
                               transportFactory,
                               protocolFactory);
server.serve();

客户端:

shared_ptr <TSSLSocketFactory> socketFactory = shared_ptr<TSSLSocketFactory>(new TSSLSocketFactory());
socketFactory->loadTrustedCertificates("server.crt");
socketFactory->authenticate(false);
shared_ptr <TSSLSocket>socket = socketFactory->createSocket(configuration.ip, configuration.port);
shared_ptr<TBufferedTransport> transport(new TBufferedTransport(socket));
shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
SkullduggeryClient client(protocol);
transport->open();

感谢您花时间阅读本文。如果有明显的错误,我会很高兴听到它。这已成为我存在的祸根太久了。太久了。

1 个答案:

答案 0 :(得分:11)

您似乎正在生成自签名证书(这很好),但您使用openssl实用程序所做的操作令人困惑。

第1行正常,它会生成一个私钥 第2行无用:输出键与输入键相同! (尝试diff要看两个键。) 第3行生成CSR,第4行实际上自我签名,因此我们将看到它们可以合并在一行中。

现在,让我们退一步让我们试着了解我们在做什么: - )

您正在使用SSL对Thrift服务器和Thrift客户端之间的通信进行身份验证和加密。我假设你想要两个:

  1. 保护客户端免受恶意服务器的攻击(代码试图执行的操作)
  2. 保护服务器免受恶意客户端的攻击(这对我来说更为重要)。
  3. 要进行HTTPS类比,(1)是经典服务器证书,(2)通常是用户的用户名/密码。但是使用Thrift SSL,我们也会通过向客户发出证书来获得相互身份验证。

    我将制作的示例将使用自签名证书。它们可以轻松地适应由openssl管理的迷你CA,我将此作为练习留给读者。

    生成服务器私钥:
    openssl genrsa -out server-key.pem 2048

    生成关联的公钥并对其进行自签名:
    openssl req -new -x509 -key server-key.pem -out server-cert.pem -days 10000

    生成客户端私钥:
    openssl genrsa -out client-key.pem 2048

    生成关联的公钥并对其进行自签名:
    openssl req -new -x509 -key client-key.pem -out client-cert.pem -days 10000

    注意:当openssl req要求"Common Name (e.g. server FQDN or YOUR name)"时,请输入将运行Thrift程序的主机的FQDN。这将不允许自定义Thrift的AccessManager类。另一方面,如果事先无法知道FQDN,则需要继承AccessManager并相应地覆盖verify()方法。请参阅TSSLSocket.cpp

    好,现在代码。

    在服务器端:

    socketFactory->server(true);是多余的,请将其删除。

    socketFactory->authenticate(false)有点误导。一个更好的名字应该是authenticatePeer。如果您说false,它将不会对客户端进行身份验证,但我们在进行相互身份验证之前就已决定。

    因此,服务器的SSL前导码是:

    try {
        signal(SIGPIPE, SIG_IGN); // See README.SSL
        shared_ptr<TSSLSocketFactory> sslSocketFactory(new TSSLSocketFactory());
        sslSocketFactory->loadPrivateKey(myKey);
        sslSocketFactory->loadCertificate(myCert);
        sslSocketFactory->authenticate(true);
        sslSocketFactory->loadTrustedCertificates(trustedCerts);
        sslSocketFactory->ciphers("HIGH:!DSS:!aNULL@STRENGTH");
        ...
        } catch (TException& tx) {
            ....
        }
    

    其中myKeyserver-key.pemmyCertserver-cert.pemtrustedCerts为...是受信任的CA的证书,或者,如果是自签名证书,客户证书。您可以在同一个文件中依次cat多个证书。在我们的示例中,我们将放置之前创建的client-cert.pem

    客户端的SSL前导码完全相同,具有正确的客户端私钥,客户端证书,以及trustedCerts,我们之前创建的对等证书server-cert.pem

    这就是全部:-)在跳转到代码之前尝试理解,如果您没有清楚了解SSL(相互)身份验证的工作原理,则很难理解错误消息。我展示的代码经过测试可以运行。

    文档方面,不幸的是,Thrift几乎没有。对于SSL,您可以看到:lib/cpp/README.SSLtest/cpp/src/TestServer.cpptest/cpp/src/TestClient.cpp。请注意TestServer.cpp不进行相互身份验证,这是一个错误恕我直言。