Java SSLException:证书中的主机名不匹配

Win*_*Win 39 java ssl https

我一直在使用以下代码连接到谷歌的服务之一.这段代码在我的本地机器上工作正常:

HttpClient client=new DefaultHttpClient();
HttpPost post = new HttpPost("https://www.google.com/accounts/ClientLogin");
post.setEntity(new UrlEncodedFormEntity(myData));
HttpResponse response = client.execute(post);
Run Code Online (Sandbox Code Playgroud)

我将此代码放在生产环境中,该环境已阻止Google.com.根据要求,他们允许我访问IP:74.125.236.52(这是Google的IP之一),允许与Google服务器进行通信.我编辑了我的hosts文件也添加了这个条目.

我仍然无法访问URL,我想知道为什么.所以我用上面的代码替换了:

HttpPost post = new HttpPost("https://74.125.236.52/accounts/ClientLogin");
Run Code Online (Sandbox Code Playgroud)

现在我收到这样的错误:

javax.net.ssl.SSLException:证书中的主机名不匹配:<74.125.236.52>!= <www.google.com>

我想这是因为Google有多个IP.我不能让网络管理员允许我访问所有这些IP - 我甚至可能没有得到这整个列表.

我现在应该怎么做 ?Java级别有解决方法吗?或者它完全掌握在网络人手中?

H6.*_*H6. 27

您还可以尝试按此处所述设置HostnameVerifier .这对我有用,可以避免这个错误.

// Do not do this in production!!!
HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;

DefaultHttpClient client = new DefaultHttpClient();

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);
DefaultHttpClient httpClient = new DefaultHttpClient(mgr, client.getParams());

// Set verifier     
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);

// Example send http request
final String url = "https://encrypted.google.com/";  
HttpPost httpPost = new HttpPost(url);
HttpResponse response = httpClient.execute(httpPost);
Run Code Online (Sandbox Code Playgroud)

  • 使用此主机名验证程序通常是一个坏主意(请参阅[此问题](http://security.stackexchange.com/q/22965/2435)). (3认同)

Vin*_*lds 22

证书验证过程将始终验证服务器提供的证书的DNS名称,以及客户端使用的URL中的服务器的主机名.

以下代码

HttpPost post = new HttpPost("https://74.125.236.52/accounts/ClientLogin");
Run Code Online (Sandbox Code Playgroud)

将导致证书验证过程验证服务器发出的证书的通用名称,即是否www.google.com匹配主机名即74.125.236.52.显然,这肯定会导致失败(您可以通过浏览https://74.125.236.52/accounts/ClientLogin器浏览到URL来验证这一点,并亲自看到产生的错误).

据称,为了安全起见,你都不愿意写自己TrustManager(和你不可以,除非你了解如何编写一个安全的),你应该看看你的数据中心建立DNS记录,以确保所有查找到www.google.com将就决心74.125.236.52; 这应该在您的本地DNS服务器或hosts您的操作系统文件中完成; 您可能还需要将条目添加到其他域.不用说,您需要确保这与ISP返回的记录一致.

  • 这不是TrustManager问题.这是HTTPS HostnameVerifier问题.DNS解决方案将解决它.没有TrustManager可以解决它. (3认同)

小智 13

我有类似的问题.我使用的是Android的DefaultHttpClient.我已经读过HttpsURLConnection可以处理这种异常.所以我创建了自定义HostnameVerifier,它使用来自HttpsURLConnection的验证器.我还将实现包装到自定义HttpClient.

public class CustomHttpClient extends DefaultHttpClient {

public CustomHttpClient() {
    super();
    SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
    socketFactory.setHostnameVerifier(new CustomHostnameVerifier());
    Scheme scheme = (new Scheme("https", socketFactory, 443));
    getConnectionManager().getSchemeRegistry().register(scheme);
}
Run Code Online (Sandbox Code Playgroud)

这是CustomHostnameVerifier类:

public class CustomHostnameVerifier implements org.apache.http.conn.ssl.X509HostnameVerifier {

@Override
public boolean verify(String host, SSLSession session) {
    HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
    return hv.verify(host, session);
}

@Override
public void verify(String host, SSLSocket ssl) throws IOException {
}

@Override
public void verify(String host, X509Certificate cert) throws SSLException {

}

@Override
public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {

}
Run Code Online (Sandbox Code Playgroud)

}


Ris*_*hra 9

httpcliet4.3.3中的一种更清洁的方法(仅适用于测试环境)如下所示.

SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
Run Code Online (Sandbox Code Playgroud)


Win*_*Win 5

谢谢Vineet Reynolds.你提供的链接持有很多用户评论 - 其中一个我在绝望中尝试过并且它有所帮助.我添加了这个方法:

// Do not do this in production!!!
HttpsURLConnection.setDefaultHostnameVerifier( new HostnameVerifier(){
    public boolean verify(String string,SSLSession ssls) {
        return true;
    }
});
Run Code Online (Sandbox Code Playgroud)

这对我来说似乎很好,虽然我知道这个解决方案是暂时的.我正在与网络人员一起确定我的hosts文件被忽略的原因.

  • 这实际上是个坏主意.顺便说一句,您可能想要在`/ etc/nsswitch.conf`中验证查找顺序,并查看是否在查找中忽略了hosts文件. (12认同)
  • 请不要将此作为接受的答案,因为这是一个非常糟糕的主意,不管是暂时的还是暂时的.在这种情况下,对你来说可能没问题,但是由于类似的问题,它不太可能被其他人发现.您也可以不使用SSL,至少在这种情况下,您不是在开玩笑任何关于安全性的人.也许你可以在确定并实际解决问题后(在与网络人员谈话之后)编辑问题,然后只接受它. (12认同)
  • 你只是有效地从你家的前门取下锁,因为你不明白如何使用钥匙. (11认同)

ora*_*oon 5

在httpclient-4.3.3.jar中,还有另一个HttpClient可供使用:

public static void main (String[] args) throws Exception {
    // org.apache.http.client.HttpClient client = new DefaultHttpClient();
    org.apache.http.client.HttpClient client = HttpClientBuilder.create().build();
    System.out.println("HttpClient = " + client.getClass().toString());
    org.apache.http.client.methods.HttpPost post = new HttpPost("https://www.rideforrainbows.org/");
    org.apache.http.HttpResponse response = client.execute(post);
    java.io.InputStream is = response.getEntity().getContent();
    java.io.BufferedReader rd = new java.io.BufferedReader(new java.io.InputStreamReader(is));
    String line;
    while ((line = rd.readLine()) != null) { 
        System.out.println(line);
    }
}
Run Code Online (Sandbox Code Playgroud)

这个HttpClientBuilder.create().build()将返回org.apache.http.impl.client.InternalHttpClient.它可以处理证书中主机名不匹配的问题.