使用HTTPS Confusion的Java HTTP帖子 - javax.net.ssl.SSLException:证书中的主机名不匹配

时间:2013-03-19 10:50:14

标签: java web-services security ssl ssl-certificate

我正在使用Apache HttpClient在某个网址上发送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已成功完成。

但我不明白这里发生了什么! 我的连接是否仍然安全? 这是正确的解决方案吗?如果没有,那么最佳解决方案是什么?

2 个答案:

答案 0 :(得分:3)

如果您未验证主机名,则根本不检查您是否正在与您打算与之交谈的实体进行通话:它可能是MITM。例如,它与disabling VERIFYHOST with Curl的问题相同。您可能也对this question on Security.SE感兴趣。

关于您的初始问题,证书中的主机名(或IP地址)需要与您要联系的主机名相匹配,即URL中的主机名。 如果您使用的是IP地址,则该IP地址必须位于证书的使用者备用名称中。 (见this question。) 通常,即使在LAN上,使用名称而不是IP地址也更容易。

编辑:考虑到您正在使用Apache Http Client 4.0.2,release notes for 4.0.3说:

  

这是在SSL中修复关键回归的紧急版本   连接管理代码。 HttpClient 4.0.2发布包括一个   改进了对多家庭主机的支持,不幸的是它有一个bug   导致默认SSL主机名验证逻辑失败。一个   尝试与HttpClient 4.0.2建立SSL连接   导致javax.net.ssl.SSLException:&#34;证书中的主机名没有&t   匹配......&#34;错误。

答案 1 :(得分:1)

重要 - 如果您允许所有主机(即禁用主机名验证),那么它肯定不安全。你不应该在生产中这样做。

我认为您可能正在使用自签名证书,这可能是此异常的根本原因。如果是,请创建一个证书,主机为localhost(或您的IP),然后尝试。在生产时,只需启用主机名验证,您的代码就可以正常运行。