8

これは、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

これは機能します。クロムで出力を確認できますが、最初にウイルスに感染するという警告が表示されます。

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 未検証証明書の例外が発生します。その行が残っていると、認証失敗の例外が発生します。

上記のスニペットをよりよく理解できるように、2 つのはるかに長いコード フラグメントを次に示します。
サーバ:

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

これを読んでくれてありがとう。明らかなエラーがある場合は、喜んでお知らせします。これは、あまりにも長い間私の存在の悩みの種でした。長すぎる。

4

1 に答える 1

11

自己署名証明書を生成しているようですが (これは問題ありません)、opensslユーティリティで行っている操作はわかりにくいものです。

1行目はOKです。秘密鍵を生成します。
行 2 は役に立ちません: 出力キーは入力キーと同じです! ( diff2 つのキーを見てみてください)。
行 3 は CSR を生成し、行 4 は実際に CSR に自己署名するため、後で説明するようにそれらを 1 行にマージできます。

さて、一歩下がって、私たちが何をしているのかを理解しようとしましょう:-)

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->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) {
        ....
    }

myKeyis server-key.pemmyCertis server-cert.pemtrustedCertsis ... は、信頼できる CA の証明書か、自己署名証明書の場合はクライアントの証明書です。cat同じファイル内で複数の証明書を次々に作成できます。この例では、client-cert.pem以前に作成したものを配置します。

クライアントの SSL プリアンブルはまったく同じで、正しいクライアント秘密鍵、クライアント証明書、およびtrustedCertsピアの証明書が含まserver-cert.pemれています。

それだけです :-) コーディングに取りかかる前に理解するようにしてください。SSL (相互) 認証がどのように機能するかを明確に理解していないと、エラー メッセージを理解するのが難しくなります。私が示したコードは動作するようにテストされています。

ドキュメンテーションに関しては、残念ながら Thrift はほとんど何もありません。SSL の場合はlib/cpp/README.SSL、 、test/cpp/src/TestServer.cppおよびが表示されtest/cpp/src/TestClient.cppます。TestServer.cppエラーIMHOである相互認証を行わないことに注意してください。

于 2012-07-03T21:59:36.167 に答える