CertificateException:找不到与ssl.someUrl.de匹配的名称

问题描述 投票:39回答:6

我正在尝试通过ssl与Java连接到我的一台服务器。我尝试了很多选项,这是我最好的尝试:

我使用以下命令生成带有推荐脚本的jssecacerts:http://blogs.oracle.com/andreas/resource/InstallCert.java:java InstallCert ssl.someUrl.de changeit

在此之后我第二次做了命令:

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

java ssl plesk
6个回答
57
投票

看起来您尝试连接的服务器的证书与其主机名不匹配。

当HTTPS客户端连接到服务器时,它会验证证书中的主机名是否与服务器的主机名匹配。证书不可靠,它必须匹配您想要与之交谈的服务器。 (作为类比,即使您相信护照是合法的,您仍然必须检查它是否是您想要与之交谈的人,而不仅仅是您认为合法的护照。)

在HTTP中,这是通过检查:

  • 证书包含与主机名匹配的DNS主题备用名称(这是标准扩展名);
  • 如果失败,主题专有名称的最后一个CN(如果需要,这是主要名称)与主机名匹配。 (参见RFC 2818.)

如果没有证书,很难说出主题替代名称是什么(尽管如果你连接浏览器并查看其内容的更多细节,你应该能够看到它。)主题专有名称似乎是:

[email protected], CN=plesk, OU=Plesk, O=Parallels, L=Herndon, ST=Virginia, C=US

(因此,如果你没有DNS的主题替代名称,那么它需要是CN = ssl.someUrl.de而不是CN = plesk:ssl.someUrl.de已经存在;我的猜测是你没有。)

您可以使用HttpsURLConnection.setHostnameVerifier(..)绕过主机名验证。编写一个自定义的HostnameVerifier并不太难以通过验证验证,尽管我建议只在证书与此处有关的证书时才这样做。您应该能够使用SSLSession参数及其getPeerCertificates()方法获取它。

(此外,您不需要像完成它那样设置javax.net.ssl。*属性,因为您仍然使用默认值。)

或者,如果您可以控制要连接的服务器及其证书,则可以创建与上述命名规则匹配的证书(CN应该足够,但主题替代名称是一种改进)。如果自签名证书足以满足您的要求,请确保其公用名(CN)是您尝试与之通信的主机名(没有完整的URL,只有主机名)。


23
投票

在Java 8中,您可以使用以下代码跳过服务器名称检查:

HttpsURLConnection.setDefaultHostnameVerifier ((hostname, session) -> true);

但是这应该仅用于开发!


14
投票

我创建了一个方法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);
}

4
投票

我在这里找到了一个很好的解决方案: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)。并且此域无法通过IP解析,因为它未在DNS中显示。

所以出现了同样的问题:如果我使用IP通过ssl连接到web服务,则无法通过证书CN = some.remote.host到达它并且它不等于我指定的主机名(即主机IP) 。

我已通过将此主机名与/ etc / hosts文件中的IP匹配来解决此问题。问题得到解决。

但是,如果Web服务托管在localhost应用服务器上,它认为应该像他的文章中描述的mkyong一样解决。


1
投票

服务器名称应与创建证书时提供的名/姓相同


1
投票

如果您正在寻找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 Notable changes in 2.0.0

解决方案:SslConfigs.SSL_ENDPOINT_IDENTIFICATION_ALGORITHM_CONFIG,“”

© www.soinside.com 2019 - 2024. All rights reserved.