【问题标题】:SSL Certificate, not authenticating via thrift, but OK via browserSSL 证书,不通过 thrift 进行身份验证,但可以通过浏览器进行身份验证
【发布时间】:2012-06-13 10:50:58
【问题描述】:

这就是我生成 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

这是来自服务器的 sn-p。老实说,我不确定每一行都在做什么,尽管我有一个好主意:

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 未经验证的证书异常。 留下那行,我得到一个身份验证失败异常。

这里有 2 个更长的代码片段,可以更好地了解上面的 sn-ps。
服务器:

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();

感谢您抽出宝贵时间阅读本文。如果有明显的错误,我会很高兴听到的。这一直是我存在的祸根太久了。太长了。

【问题讨论】:

    标签: c++ ssl openssl thrift


    【解决方案1】:

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

    第 1 行没问题,它会生成一个私钥。
    第2行没用:输出键和输入键一样! (试试diff这两个键看看)。
    第 3 行生成一个 CSR,第 4 行实际上是对它进行自签名,因此我们可以将它们合并到一行中。

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

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

    1. 保护客户端免受恶意服务器的侵害(您的代码试图做的事情)
    2. 保护服务器免受恶意客户端的侵害(这对我来说似乎更重要)。

    打个比方 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-&gt;server(true); 是多余的,删除它。

    socketFactory-&gt;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 不进行相互身份验证,恕我直言,这是一个错误。

    【讨论】:

      猜你喜欢
      • 2018-06-15
      • 2010-11-08
      • 1970-01-01
      • 1970-01-01
      • 2012-09-12
      • 2017-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多