Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/371.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何解决“问题”;java.security.cert.CertificateException:不存在主题替代名称”;错误?_Java_Ssl_Https_Certificate_Ssl Certificate - Fatal编程技术网

如何解决“问题”;java.security.cert.CertificateException:不存在主题替代名称”;错误?

如何解决“问题”;java.security.cert.CertificateException:不存在主题替代名称”;错误?,java,ssl,https,certificate,ssl-certificate,Java,Ssl,Https,Certificate,Ssl Certificate,我有一个JavaWeb服务客户端,它通过HTTPS使用web服务 import javax.xml.ws.Service; @WebServiceClient(name = "ISomeService", targetNamespace = "http://tempuri.org/", wsdlLocation = "...") public class ISomeService extends Service { public ISomeService() {

我有一个JavaWeb服务客户端,它通过HTTPS使用web服务

import javax.xml.ws.Service;

@WebServiceClient(name = "ISomeService", targetNamespace = "http://tempuri.org/", wsdlLocation = "...")
public class ISomeService
    extends Service
{

    public ISomeService() {
        super(__getWsdlLocation(), ISOMESERVICE_QNAME);
    }
当我连接到服务URL(
https://AAA.BBB.CCC.DDD:9443/ISomeService
),我得到了异常
java.security.cert.CertificateException:没有主题替代名称出现

为了修复它,我首先运行了
openssl s_client-showcerts-connectaaa.BBB.CCC.DDD:9443>certs.txt
,并在文件
certs.txt
中获得了以下内容:

CONNECTED(00000003)
---
Certificate chain
 0 s:/CN=someSubdomain.someorganisation.com
   i:/CN=someSubdomain.someorganisation.com
-----BEGIN CERTIFICATE-----
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-----END CERTIFICATE-----
---
Server certificate
subject=/CN=someSubdomain.someorganisation.com
issuer=/CN=someSubdomain.someorganisation.com
---
No client certificate CA names sent
---
SSL handshake has read 489 bytes and written 236 bytes
---
New, TLSv1/SSLv3, Cipher is RC4-MD5
Server public key is 512 bit
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : RC4-MD5            
    Session-ID: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    Session-ID-ctx:                 
    Master-Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    Key-Arg   : None
    Start Time: 1382521838
    Timeout   : 300 (sec)
    Verify return code: 21 (unable to verify the first certificate)
---
好了,现在我需要

  • 提取
    ----开始证书---
    ----结束证书---
    之间的
    certs.txt
    部分
  • 修改它,使证书名称等于
    AAA.BBB.CCC.DDD
  • 然后使用
    keytool-importcert-file fileWithModifiedCertificate
    导入结果(其中
    fileWithModifiedCertificate
    是操作1和2的结果)
  • 这是正确的吗

    如果是这样,我如何才能使步骤1中的证书与基于IP的地址(
    AAA.BBB.CCC.DDD
    )一起工作

    更新1(23.10.2013 15:37 MSK):在对a的回答中,我读到以下内容:

    如果您无法控制该服务器,请使用其主机名(提供 现有服务器中至少有一个CN与该主机名匹配 证书)


    “使用”的确切含义是什么?

    根据客户端的请求执行证书身份验证

    当您的客户使用
    https://xxx.xxx.xxx.xxx/something
    (其中
    xxx.xxx.xxx.xxx
    是一个IP地址),将根据该IP地址检查证书标识(理论上,仅使用IP SAN扩展)

    如果您的证书没有IP SAN,但有DNS SAN(或者如果没有DNS SAN,则为主题DN中的一个通用名称),您可以通过让客户端使用具有该主机名的URL(或者证书将对其有效的主机名,如果存在多个可能的值)来实现这一点。例如,如果您的证书有
    www.example.com
    的名称,请使用
    https://www.example.com/something

    当然,您需要该主机名才能解析为该IP地址


    此外,如果存在任何DNS SAN,则主题DN中的CN将被忽略,因此在此情况下,请使用与其中一个DNS SAN匹配的名称。

    我通过使用以下方法禁用HTTPS检查修复了此问题:

    我将以下代码放入
    ISomeService
    类中:

    static {
        disableSslVerification();
    }
    
    private static void disableSslVerification() {
        try
        {
            // Create a trust manager that does not validate certificate chains
            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) {
                }
            }
            };
    
            // Install the all-trusting trust manager
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    
            // Create all-trusting host name verifier
            HostnameVerifier allHostsValid = new HostnameVerifier() {
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            };
    
            // Install the all-trusting host verifier
            HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
    }
    
    因为我正在使用
    https://AAA.BBB.CCC.DDD:9443/ISomeService
    仅出于测试目的,这是一个足够好的解决方案,但不要在生产中这样做

    请注意,您还可以为“一次一个连接”禁用SSL,例如:


    我也有同样的问题,用这个代码解决了。 我将此代码放在第一次调用Web服务之前

    javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
      new javax.net.ssl.HostnameVerifier(){
    
          public boolean verify(String hostname,
                 javax.net.ssl.SSLSession sslSession) {
              return hostname.equals("localhost"); // or return true
          }
      });
    
    它很简单,也很好用


    是原始源。

    通过使用完整的URL“qatest.ourCompany.com/webService”而不是“qatest/webService”,解决了我获取此错误的问题。原因是我们的安全证书有一个通配符,即“*.ourCompany.com”。一旦我输入完整地址,例外情况就消失了。希望这有帮助。

    在hosts文件中添加您的IP地址,该文件位于C:\Windows\System32\drivers\etc文件夹中。 还要添加IP地址的IP和域名。 例子: aaa.bbb.ccc.dddabc@def.com

    要导入证书:

  • 从服务器提取证书,例如
    openssl s_客户端-showcerts-connect AAA.BBB.CCC.DDD:9443>certs.txt
    这将以PEM格式提取证书
  • 将证书转换为DER格式,因为这是keytool期望的格式,例如
    openssl x509-in-certs.txt-out-certs.DER-outform-DER
  • 现在您要将此证书导入系统默认的“cacert”文件。找到Java安装的系统默认“cacerts”文件。看看
  • 将证书导入该cacerts文件:
    sudo keytool-importcert-file certs.der-keystore
    默认cacerts密码为“changeit”

  • 如果证书是为FQDN颁发的,并且您正试图通过Java代码中的IP地址进行连接,那么这可能应该在您的代码中得到修复,而不是弄乱证书本身。将代码更改为通过FQDN连接。如果FQDN无法在您的开发人员计算机上解析,只需将其添加到您的主机文件,或使用可解析此FQDN的DNS服务器配置您的计算机。

    我已通过以下方法解决了此问题

    1.创建一个类。该类有一些空的实现
    2.创建方法
  • 调用引发异常的disableSSL()方法。它工作得很好

  • 您可能不想禁用所有ssl验证,因此您可以通过以下方式禁用主机名验证,这比备选方案更安全:

    HttpsURLConnection.setDefaultHostnameVerifier(
        SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    
    [编辑]


    正如conapart3
    SSLConnectionSocketFactory.ALLOW\u ALL\u HOSTNAME\u VERIFIER
    所述,现在已不推荐使用,因此它可能会在以后的版本中被删除,因此将来您可能会被迫推出自己的,尽管我仍然会说,我会避开任何关闭所有验证的解决方案。

    我以正确的方式解决了这个问题,在证书中添加了subject alt name,而不是像其他答案所建议的那样对代码进行任何更改或禁用SSL。如果您清楚地看到异常显示“缺少Subject alt name”,那么正确的方法应该是添加它们

    请看这个

    上述错误意味着您的JKS文件缺少您尝试访问应用程序所需的域。您将需要使用Open SSL和密钥工具添加多个域

  • 将openssl.cnf复制到当前目录中
  • echo'[subject\u alt\u name]>>openssl.cnf
  • echo'subjectAltName=DNS:example.mydoma
    
    class MyTrustManager implements X509TrustManager {
    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return null;
    }
    
    public void checkClientTrusted(X509Certificate[] certs, String authType) {
    }
    
    public void checkServerTrusted(X509Certificate[] certs, String authType) {
    }
    
    @Override
    public void checkClientTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString)
            throws CertificateException {
        // TODO Auto-generated method stub
    
    }
    
    @Override
    public void checkServerTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString)
            throws CertificateException {
        // TODO Auto-generated method stub
    
    }
    
    private static void disableSSL() {
        try {
            TrustManager[] trustAllCerts = new TrustManager[] { new MyTrustManager() };
    
            // Install the all-trusting trust manager
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HostnameVerifier allHostsValid = new HostnameVerifier() {
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            };
            HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    HttpsURLConnection.setDefaultHostnameVerifier(
        SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    
    openssl pkcs12 -export -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -export -in
    self-signed.pem -inkey private.key -name myalias -out keystore.p12
    
    keytool -importkeystore -destkeystore keystore.jks -deststoretype PKCS12 -srcstoretype PKCS12 -srckeystore keystore.p12
    
    keytool -export -keystore keystore.jks -alias myalias -file selfsigned.crt
    
    sudo keytool -importcert -file selfsigned.crt -alias myalias -keystore /Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/jre/lib/security/cacerts
    
    -Dcom.sun.jndi.ldap.object.disableEndpointIdentification=true
    
        HttpsURLConnection urlConnection = (HttpsURLConnection) new URL("https://WW.XX.YY.ZZ/api/verify").openConnection();
        urlConnection.setSSLSocketFactory(socketFactory());
        urlConnection.setDoOutput(true);
        urlConnection.setRequestMethod("GET");
        urlConnection.setUseCaches(false);
        urlConnection.setHostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession sslSession) {
                return true;
            }
        });
        urlConnection.getOutputStream();
    
    new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession sslSession) {
                return true;
            }
        }
    
    SSLContext sslContext = new SSLContextBuilder()
            .loadTrustMaterial(new URL("file:pathToServerKeyStore"), storePassword)
    //        .loadKeyMaterial(new URL("file:pathToClientKeyStore"), storePassword, storePassword)
            .build();
    SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
    CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(socketFactory).build();
    HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(client);
    RestTemplate restTemplate = new RestTemplate(factory);
    
      RestTemplate restTemplate = new RestTemplate();   
      TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
                @Override
                public boolean isTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) {
                    return true;
                }
    
            };
    
            SSLContext sslContext = null;
            try {
                sslContext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy)
                        .build();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (KeyManagementException e) {
                e.printStackTrace();
            } catch (KeyStoreException e) {
                e.printStackTrace();
            }
            SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
            CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();
            HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
            requestFactory.setHttpClient(httpClient);
    
            restTemplate.setRequestFactory(requestFactory);
    }
    
    Subject Alternative Name:
    DNS: example.com
    
    **keytool -genkey -keyalg RSA -keystore keystore.jks -keysize 2048 -alias <IP_ADDRESS> -ext san=ip:<IP_ADDRESS>**
    
    **openssl s_client -showcerts -connect <IP_ADDRESS>:443 < /dev/null | openssl x509 -outform PEM > myCert.pem**
    
    **keytool -import -trustcacerts -keystore /home/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.242.b08-1.el7.x86_64/jre/lib/security/cacerts -alias <IP_ADDRESS> -file ./mycert.pem**
    
    javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
                (hostname, sslSession) -> true);