4

Apache HttpClient を使用して、いくつかの URL で https POST を送信しています。

HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
HttpResponse response = httpClient.execute(httpPost);

そして私は得る:

javax.net.ssl.SSLException: hostname in certificate didn't match: <*.*.*.*> != <*.url 

検索した後、stackoverflowで解決策を見つけました:

HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
SchemeRegistry registry = new SchemeRegistry();
SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
registry.register(new Scheme("https", socketFactory, 443));
SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
HttpClient httpClient = new DefaultHttpClient(mgr, client.getParams());
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);

そして、POST は正常に完了しました。

しかし、ここで何が起こっているのかわかりません!私の接続はまだ安全ですか?これは正しい解決策ですか?そうでない場合、最善の解決策は何ですか?

4

2 に答える 2

3

ホスト名を確認していない場合は、話したいエンティティと話していることを確認していないだけです。代わりに、MITM である可能性があります。たとえば、 Curl で VERIFYHOST を無効にするのと同じ問題です。Security.SE に関するこの質問にも興味があるかもしれません。

最初の問題に関しては、証明書のホスト名 (または IP アドレス) が、接続しようとしていたホスト名、つまり URL のホスト名と一致する必要があります。IP アドレスを使用している場合、その IP アドレスは証明書のサブジェクトの別名に含まれている必要があります。(この質問を参照してください。) 一般に、LAN 上であっても、IP アドレスよりも名前を使用する方が簡単です。

編集: Apache Http Client 4.0.2 を使用していることを考慮して、4.0.3 のリリース ノートには次のように記載されています。

これは、SSL 接続管理コードの重大なリグレッションを修正する緊急リリースです。HttpClient 4.0.2 リリースには、マルチホーム ホストの改善されたサポートが含まれていましたが、残念ながら、デフォルトの SSL ホスト名検証ロジックが失敗するバグがありました。HttpClient 4.0.2 との SSL 接続を確立しようとすると、javax.net.ssl.SSLException: "証明書のホスト名が一致しませんでした ..." エラーが発生する可能性があります。

于 2013-03-19T11:55:43.970 に答える
1

重要-すべてのホストを許可している場合(つまり、ホスト名の検証を無効にしている場合)、それは確かに安全ではありません。これを本番環境で行うべきではありません。

おそらく、この例外の根本的な原因である可能性のある自己署名証明書を使用していると思います。はいの場合は、ホストをlocalhost(またはIP)として証明書を作成してから、試してください。本番環境では、ホスト名の検証を有効にするだけで、コードは正常に実行されます。

于 2013-03-19T10:54:02.180 に答える