Javaを使用して、sslを介してサーバーの1つに接続しようとしています。私はここで多くのオプションを試しました私の最善の試みです:
私は、recommendetスクリプトでjssecacertsを生成します: http://blogs.Oracle.com/andreas/resource/InstallCert.Java コマンド:Java InstallCert ssl。 someUrl.de changeit
この後、2回目のコマンドを実行しました。
Loading KeyStore jssecacerts...
Opening connection to ssl.someUrl.de:443...
Starting SSL handshake...
No errors, certificate is already trusted
Server sent 1 certificate(s):
1 Subject [email protected], CN=plesk, OU=Plesk, O=Parallels, L=Hernd
on, ST=Virginia, C=US
Issuer [email protected], CN=plesk, OU=Plesk, O=Parallels, L=Hernd
on, ST=Virginia, C=US
sha1 f1 0d 2c 54 05 e1 32 19 a0 52 5e e1 81 6c a3 a5 83 0d dd 67
md5 f0 b3 be 5e 5f 6e 90 d1 bc 57 7a b2 81 ce 7d 3d
Enter certificate to add to trusted keystore or 'q' to quit: [1]
ファイルをデフォルトのディレクトリにコピーし、証明書をJava trustStoreにロードしました
System.setProperty("javax.net.ssl.trustStore", "C:\\Program Files (x86)\\Java\\jre6\\lib\\security\\jssecacerts");
System.setProperty("javax.net.ssl.trustStorePassword","changeit");
その後、私は接続しようとします
URL url = new URL("https://ssl.someUrl.de/");
URLConnection conn = url.openConnection();
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
そして、3行目にエラーが表示されます:(ssl.someUrl.deに一致する名前が見つかりません)
javax.net.ssl.SSLHandshakeException: Java.security.cert.CertificateException: No name matching ssl.someUrl.de found
これはデフォルトのplesk証明書の原因ですか、それとも何か間違っていますか?
セットアップ:JRE 6.20、Netbeans 6.8、Windows7 64bit
接続しようとしているサーバーの証明書がホスト名と一致しないようです。
HTTPSクライアントがサーバーに接続するとき、証明書のホスト名がサーバーのホスト名と一致することを確認します。証明書を信頼するだけでは不十分であり、通信するサーバーにも一致する必要があります。 (たとえると、たとえパスポートが正当であると信頼していても、正当であると信頼するパスポートだけでなく、話したい相手のパスポートであることを確認する必要があります。)
HTTPでは、次のことを確認することでこれを行います。
証明書には、ホスト名に一致するDNSサブジェクト代替名(これは標準の拡張子)エントリが含まれています。
それに失敗すると、サブジェクトの識別名の最後のCN(必要に応じてメイン名)がホスト名と一致します。 (RFC 2818を参照してください。)
証明書がないとサブジェクトの別名が何であるかを知ることは困難です(ただし、ブラウザに接続してその内容を詳細に確認すると、表示できるはずです)。サブジェクトの識別名は次のように見えます。
[email protected], CN=plesk, OU=Plesk, O=Parallels, L=Herndon, ST=Virginia, C=US
(したがって、DNS = ssl.someUrl.deのサブジェクト代替名がまだない場合は、CN = pleskではなくCN = ssl.someUrl.deにする必要があります。私は推測しないでしょう。)
HttpsURLConnection.setHostnameVerifier(..) を使用して、ホスト名の検証をバイパスできる場合があります。証明書がここで特に関係している場合にのみ行うことをお勧めしますが、検証のベースとなるカスタムHostnameVerifierを書くのはそれほど難しくないはずです。 SSLSession引数とそのgetPeerCertificates()メソッドを使用して、それを取得できるはずです。
(さらに、とにかくデフォルト値を使用しているため、javax.net.ssl。*プロパティを設定する必要はありません。)
あるいは、接続先のサーバーとその証明書を制御できる場合は、上記の命名規則に一致する証明書を作成できます(サブジェクトの別名は改善されていますが、CNで十分です)。自己署名証明書で名前に十分な場合は、その共通名(CN)が通信しようとしているホスト名(完全なURLではなく、ホスト名)であることを確認してください。
Java 8では、次のコードでサーバー名のチェックをスキップできます。
HttpsURLConnection.setDefaultHostnameVerifier ((hostname, session) -> true);
ただし、これは開発でのみ使用する必要があります!
メソッドfixUntrustCertificate()を作成したので、信頼できるCAにないドメインを扱っている場合、リクエストの前にメソッドを呼び出すことができます。このコードは、Java1.4以降で機能します。この方法は、すべてのホストに適用されます。
public void fixUntrustCertificate() throws KeyManagementException, NoSuchAlgorithmException{
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public Java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new Java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// set the allTrusting verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
}
私はここで良い解決策を見つけました: http://www.mkyong.com/webservices/jax-ws/Java-security-cert-certificateexception-no-name-matching-localhost-found/
しかし、私の問題は少し異なり、解決方法も異なりました。
Webサービスはリモートホストにありました。例: https://some.remote.Host/MyWebService?wsdl
ただし、すべてのクライアントに対してIPでのみ使用可能でしたが、ドメインsome.remote.Host(CN = some.remote.Host)に対して証明書が作成されました。また、このドメインはDNSに提示されていないため、IPで解決できません。
そのため、同じ問題が発生しました。SSLを使用してWebサービスに接続するためにIPを使用すると、証明書CN = some.remote.Hostで到達できず、指定したホスト名(ホストIP)と等しくない。
このホスト名を/ etc/hostsファイルのIPと照合することで解決しました。問題は修正されました。
ただし、Webサービスがlocalhostアプリサーバーでホストされている場合は、彼の記事で説明されているmkyongのように解決する必要があると考えています。
Kafkaエラーを探している場合は、Kafkaのバージョンを1.xから2.xにアップグレードしたことが原因である可能性があります。
javax.net.ssl.SSLHandshakeException:一般的なSSLEngine問題... javax.net.ssl.SSLHandshakeException:一般的なSSLEngine問題... Java.security.cert.CertificateException:一致する名前がありません***が見つかりました
または
[Producer clientId = producer-1]ノード-2への接続は、SSLハンドシェイクに失敗したため、認証に失敗しました
Ssl.endpoint.identification.algorithmのデフォルト値がhttpsに変更され、ホスト名検証が実行されます(そうでない場合は中間者攻撃が可能です)。 ssl.endpoint.identification.algorithmを空の文字列に設定して、以前の動作を復元します。 Apache Kafka 2.0.0の注目すべき変更点
解決策:SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG、 ""
サーバー名は、証明書の作成中に指定した姓/名と同じにする必要があります