大規模なJavaアプリケーションに追加するモジュールは、他社のSSLで保護されたWebサイトと通信する必要があります。問題は、サイトが自己署名証明書を使用していることです。中間者攻撃が発生していないことを確認するための証明書のコピーがあります。サーバーへの接続が成功するように、この証明書をコードに組み込む必要があります。
基本的なコードは次のとおりです。
void sendRequest(String dataPacket) {
String urlStr = "https://host.example.com/";
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setMethod("POST");
conn.setRequestProperty("Content-Length", data.length());
conn.setDoOutput(true);
OutputStreamWriter o = new OutputStreamWriter(conn.getOutputStream());
o.write(data);
o.flush();
}
自己署名証明書の追加処理がない場合、これはconn.getOutputStream()で終了しますが、次の例外があります。
Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
....
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
....
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
理想的には、私のコードは、Javaに、この1つの自己署名証明書を受け入れるように教える必要があります。これは、アプリケーションのこの1つの場所であり、他の場所ではありません。
証明書をJREの認証局ストアにインポートできることを知っています。これにより、Javaがそれを受け入れることができるようになります。それは私が助けることができれば私が取りたいアプローチではありません。お客様が使用しない可能性のある1つのモジュールに対して、お客様のすべてのマシンで実行することは非常に侵襲的であるように思われます。同じJREを使用する他のすべてのJavaアプリケーションに影響します。このサイトにアクセスする他のJavaアプリケーションの確率はゼロですが、私はそれが好きではありません。また、これは簡単な操作ではありません。UNIXでは、この方法でJREを変更するためのアクセス権を取得する必要があります。
また、カスタムチェックを行うTrustManagerインスタンスを作成できることも確認しました。この1つの証明書を除くすべてのインスタンスで、実際のTrustManagerに委任するTrustManagerを作成できる可能性もあるようです。しかし、TrustManagerはグローバルにインストールされているようで、アプリケーションからの他のすべての接続に影響を与えると思います。それも私にはまったく適切な匂いではありません。
自己署名証明書を受け入れるようにJavaアプリケーションを設定するための推奨、標準、または最良の方法は何ですか?上記で考えているすべての目標を達成できますか、それとも妥協する必要がありますか?ファイルとディレクトリ、構成設定、およびほとんどまたはまったくコードを含まないオプションはありますか?