5

私の仕事は、(以前は HTTP) Web サービスを HTTPS で保護することです。退職した同僚から、SSLEngine既存のサーバーの TCP レイヤーと HTTP レイヤーの間にオブジェクトを挿入するコードを継承しました。私の知る限り、このコードは正しく動作します。SSLEngineからを取得しますSSLContext.createSSLEngine()が、適切な を作成する方法がわかりSSLContextません。

SSLEngineそれ自体は、その javadoc に美しい概念の紹介がありますが、残念ながら、私が自分自身にインターフェースする必要のない部分です。一方、SSLContext.init()は非常にまばらに文書化されており、「認証キーのソース」と「ピア認証の信頼決定のソース」を渡す必要があるとだけ言っていますが、それが何であるかはわかりません。これらのパラメーターの型に関するドキュメント (通常は次に理解するために試みるものです) は、何も言わないという点で一般的であり、クラスのドキュメントSSLContextも役に立たないほど簡潔です。

Java サーバーが最終的に直接処理することになるドメインで Apache が HTTPS を提供できるようにする、一連の ascii-armored .crt.pem、およびファイルが提供されます。.key私はそれらを何らかの形でSSLContextまたはにロードする必要があると思いますSSLEngineが、それが適切な場所であるかどうかSSLContext.init()さえわかりません (ただし、他に多くの場所があるようには見えません)。

これを行う方法を実際に理解するには、どのドキュメントを読むことから始めるべきですか?

私の Google の試みでは、品質とセキュリティが不明な半文書化されていないサンプル コードが多数生成されます。また、「独自のキー プロバイダーの作成方法」などの高度なウォークスルーもいくつか生成されますが、JREの最も基本的な使用法に関する全体的な概念の紹介はありません。クラス。

特にこれはセキュリティに関連しているため、コピー アンド ペーストのサンプル コードは役に立たず、多かれ少なかれ希望どおりに動作するようになるまで、あてもなく試してみます。さまざまな部品が実際にどのように組み合わされるのかについて、高レベルの概念を理解する必要があります。

(ドキュメントが十分に詳細であり、実際にSSLクライアント認証を行う方法も理解できる場合はボーナスポイントですが、それはすぐに緊急ではありません).

4

2 に答える 2

4

詳細なドキュメントが必要な場合は、JSSE リファレンス ガイド、より具体的にはSSLContext セクションを参照してください。

デフォルト値 ( に渡す場合null)SSLContext.init(...)はデフォルトで適切ですが、これらのデフォルト値が何であるかを理解したい場合があります (カスタマイズのセクションを参照してください)。

キーストアにはデフォルトはありません (トラストストアだけです。クライアント証明書認証が必要な場合は、とにかくカスタマイズする必要があります)。

SSLContext通常、次のように初期化できます。

KeyStore ks = KeyStore.getInstance(...); // Load the keystore
ks.load(...); // Load as required from the inputstream of your choice, for example.

KeyStore ts = KeyStore.getInstance(...); // Load the truststore
ts.load(...);

KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, <the key password>);

TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ts);

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

おそらく、キーストアとトラストストアの違いについて、この回答にも興味があるかもしれません。要するに、どちらもストレージの意味での「キーストア」ですが、キーストアは、証明書 (+チェーン) と関連する秘密鍵 (つまり、サーバー上のサーバー証明書と秘密鍵、およびクライアント証明書と秘密鍵) を格納する場所です。トラストストアは、リモート パーティがその証明書を提示するときに、信頼できる CA 証明書またはリモート証明書 (証明書ではないため、秘密鍵なし) を格納する場所です。

キー/証明書ファイルをどうするかに関しては、この回答PCKS12で説明されているように構築できるtype のキーストアを使用するのが最も簡単です。

編集:(コメントに続く)

それで、私がサーバーであり、まだ SSL クライアント認証を行っていない場合、null の TrustManager を回避できることは正しく理解されていますか?

はい。

しかし、クライアント認証を行う場合、接続できるすべてのクライアントの公開鍵を含む TrustManager を提供する必要がありますか?

通常はありません。これらのクライアント証明書を発行した CA の CA 証明書を提供します。このインフラストラクチャがない場合 (または構築中でクライアント証明書がまだない場合) は、独自の PKI を作成するか、有名な CA からクライアント証明書を購入することを検討する必要があります。

自己署名証明書を (任意の CA から独立して) 受け入れ、事前定義されたリストのフィンガープリントを使用してそれらを検証する TrustManager を構築することもできますが、これには多くの問題があります (特に、サーバーが正しい証明書を要求する方法)。 )、PKI の目的の一部を複製することになる可能性があります。あなたが何をしているのかをもっと理解しない限り、それは私がお勧めするものではありません.

それは少し残念です。承認されたクライアントのフィンガープリントを取得してから、実際のクライアントが認証したフィンガープリントと比較する必要がある前に、リクエスト URL を取得するまで待っていればよかったのにと思いました。

ここでは、まったく別の側面について話しています。要求された URL を最初に取得したい場合は、証明書を要求する前に、再ネゴシエーションを使用する必要があります。HTTP レイヤーはSSLEngine、新しいハンドシェイクをトリガーするように要求するために、 と通信する必要があります (クライアント証明書を要求するように設定されています)。

SSLEngine一般に、Java での SSL/TLS への簡単な道筋ではありませんが、非同期再ネゴシエーションは非常にトリッキーになる可能性があります。実際、そのセマンティクスはアプリケーション層ではあまり明確ではありません。HTTP リクエストを受信した後に再ネゴシエーションをトリガーすることは十分に可能ですが、同時にレスポンスを送信している最中でもあります (パイプライン化された非同期のリクエスト/レスポンスがある可能性があるため)。技術的には、新しいハンドシェイクは両方のパイプに影響します。

全体として、再ネゴシエーションかどうかは、クライアント証明書をどのように信頼するかを確認することとはまったく関係ありません。アプリケーション レイヤー (SSL/TLS レイヤーではなく) に証明書の検証を行う方法を本当に実行したい場合は、X509TrustManagerすべてを信頼する (SSL/TLS レイヤーでの検証をバイパスする)を作成する必要があります。アプリケーションにSSLSession(ピア証明書)から証明書を取得させ、そこで検証を行います。全体として、これは自己署名証明書を受け入れて手動で検証するのと非常によく似ています。それは可能ですが、PKI モデルからステップアウトすることになり、そのためにカスタム コードが必要になります (デフォルトで使用されるように API を使用するのではなく)。

これらすべてに慣れていない場合は、このアプローチを避けます。テスト用の CA を設定してみて、最初にその仕組みを学んでください。CA の使用または手動の指紋認証の実行に関する全体的な問題は、最終的にはより管理上の問題になります。それは、関係者間で証明書を配布する方法によって定義されます。

また、<the key password>ここで何をしていますか?これは、どこかのホスティング施設の無人サーバーで実行することになっています。起動中 (たとえば、停電の後) に誰かがパスワードを入力するのを待つことはできません。

パスワードを設定する必要があります。ほとんどのサーバーは、必要に応じて構成ファイルから読み取ります (さらに悪いことに、ハードコーディングすることもできます)。

于 2012-08-14T19:39:22.483 に答える
0

回答パート1:

KeyManagerをSSLContextに指定する必要があります。これにより、サーバーをビーイングするSSLContextは、KeyManagerが公開鍵および秘密鍵として格納するものと同じようにクライアントに提示できます。

SSLContextにTrustManagerを与えて、クライアントを認証できるようにする必要があります。

編集:回答パート2:

これらすべてのクラスとインターフェイスにより、さまざまなサービスプロバイダーをあらゆる種類(秘密鍵の管理、クライアント認証の管理、使用するSSLエンジンなど)に使用できます。

しかし、sunは、適度に安全な独自のデフォルト実装を提供します。

したがって、カスタムまたはデフォルトではないものを使用する場合は、通常、これをAPIに深く掘り下げるだけです。

編集:回答パート3:

通常、SSLSocketを使用して、プレーンソケットを配置します(またはSSLSocketを作成するため、プレーンソケットも作成されます)。

ssl通信自体に干渉したい場合は、SSLContextとSSLSessionを使用します。ソケットを使わない場所でも。

于 2012-08-14T19:23:46.277 に答える