Java证书异常:“找不到与IP地址匹配的主题备用名称...”

19

我正在尝试将自签名证书应用到我的Web服务器上,它已经在Firefox和Chrome中(在服务器本身和远程机器上)运行正常... 但是我无法让它在Java中工作。我已经创建了一个包含我的证书的密钥库文件,但每次尝试连接服务器时,都会出现SSLHandshakeException错误:javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names matching IP address 192.168.178.71 found

我用于此测试的代码如下:

public static void main(String[] args) {
         System.setProperty("javax.net.ssl.keyStore",                    HTTPStest.class.getResource("keystore.jks").getFile());
            System.setProperty("javax.net.ssl.keyStorePassword",           "lead"); 
        URL url;
            InputStream is = null;
            BufferedReader br;
            String line;

            try {
                url = new URL("https://192.168.178.71/");
                is = url.openStream();  // throws an IOException
                br = new BufferedReader(new InputStreamReader(is));

                while ((line = br.readLine()) != null) {
                    System.out.println(line);
                }
            } catch (MalformedURLException mue) {
                 mue.printStackTrace();
            } catch (IOException ioe) {
                 ioe.printStackTrace();
            } finally {
                try {
                    if (is != null) is.close();
                } catch (IOException ioe) {
                    // nothing to see here
                }
            }

    }

当我使用openssl检查我的证书时,它会给出以下结果:

 Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 2 (0x2)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=DE, ST=BY, L=MU, O=LEAD, CN=LEAD CA/emailAddress=test@gmail.com
        Validity
            Not Before: Mar 20 00:55:13 2015 GMT
            Not After : Mar 17 00:55:13 2025 GMT
        Subject: C=DE, ST=BY, L=BE, CN=192.168.178.71
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:ed:9b:27:2b:ab:7d:88:48:a3:21:54:98:24:be:
                    2d:72:4a:de:9c:05:de:95:3a:01:d5:46:09:d2:9c:
                    9f:29:b0:12:0c:86:28:88:51:a3:b9:c9:93:33:3c:
                    8a:5c:f2:fe:49:e2:1e:9e:5a:4b:fb:63:41:9a:13:
                    e5:bc:03:77:a0:5e:f2:b1:1f:db:f9:a4:03:07:8c:
                    41:54:8c:bc:2e:da:cd:72:67:5b:2f:d5:83:fd:d0:
                    bf:ea:bb:49:e0:21:2f:b3:f2:51:57:7c:81:d2:4b:
                    91:12:73:13:6a:29:3b:59:90:2d:8d:50:cc:2b:f2:
                    76:a8:41:ac:0a:11:8b:63:3b:d4:5c:91:5c:1e:41:
                    33:6f:3e:fe:ed:f4:c3:26:77:d9:e2:0b:2c:09:5c:
                    20:31:09:59:19:5c:15:75:eb:15:ef:b8:d8:7d:a2:
                    2d:f4:f8:7f:3a:7c:e0:ad:c0:3b:86:1e:4f:b1:b9:
                    c3:60:f8:fa:3c:5a:5a:72:bf:f9:95:c3:d4:8d:2b:
                    22:3f:f8:a2:37:b3:c2:16:fa:9e:2d:f9:b5:78:6d:
                    4f:88:95:84:12:f3:f5:c2:09:9f:51:ed:73:da:4d:
                    9b:c3:2f:99:6d:d7:e9:f3:e0:c4:8b:73:09:25:1f:
                    93:5c:dc:d7:fa:5c:47:59:ff:70:70:09:72:4a:8c:
                    3f:c5
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                FD:5F:79:74:31:E3:12:22:50:F8:C5:BE:A7:45:8B:10:65:8F:FC:A8
            X509v3 Authority Key Identifier: 
                keyid:C5:2F:3A:53:A7:AF:96:E2:25:09:46:8A:11:B6:B9:5D:79:55:04:D9

            X509v3 Basic Constraints: 
                CA:FALSE
            X509v3 Key Usage: 
                Digital Signature, Key Encipherment
            X509v3 Subject Alternative Name: 
                DNS:192.168.178.71, DNS:www.example.com, DNS:mail.example.com, DNS:ftp.example.com
            Netscape Comment: 
                OpenSSL Generated Certificate
    Signature Algorithm: sha256WithRSAEncryption
         7a:17:44:18:8e:31:11:b9:0a:fc:bf:d2:61:2f:16:24:56:24:
         11:04:9e:2e:dc:65:d1:31:12:af:3d:ff:57:80:6b:45:70:f2:
         e3:d8:2d:dd:d1:1d:05:ba:2e:92:d1:80:e8:93:0c:02:b2:47:
         d1:5c:10:54:cb:4d:e5:52:f4:1d:c4:d2:26:a5:8e:4c:a3:44:
         c0:6a:1d:74:27:89:6f:f4:dc:90:cc:3b:59:50:b7:38:5b:31:
         da:21:01:d4:e6:4f:7a:23:23:d5:c5:61:29:32:1a:1e:bb:f9:
         e1:3b:4f:a9:d8:d6:1d:f5:cf:15:04:18:8b:77:28:44:ef:ae:
         33:8c:1e:72:d6:8c:c4:cc:7c:17:b8:f4:e5:d0:34:4f:d5:3d:
         d7:59:4d:40:f3:42:1e:0c:26:98:73:98:a5:c2:d9:ea:2b:2a:
         05:c3:f5:0b:e1:b6:d7:91:4a:09:15:21:1b:bc:d1:96:5e:bd:
         47:9f:ab:27:e9:44:fc:00:e1:49:e4:74:1b:48:ff:56:01:03:
         e7:9b:d2:bc:0a:53:39:95:52:5f:de:d8:fe:10:e8:53:5f:b4:
         de:18:2d:50:a4:12:f8:48:37:66:4b:e1:18:21:69:ce:f3:0d:
         2f:3d:03:22:bf:f6:91:3f:23:0b:58:4f:5f:be:82:67:ab:65:
         98:15:e0:78:33:c6:50:38:39:42:ac:a5:bd:13:16:ca:58:64:
         ce:a7:e8:88:e8:2f:eb:d5:7e:9e:75:51:da:50:b4:41:d1:83:
         a8:a8:a3:18:25:b8:87:9d:c8:18:a0:db:7a:57:b1:31:e3:34:
         a8:92:b7:4b:75:c4:34:09:3d:a2:de:69:b2:d5:2f:9e:97:b7:
         c8:b5:df:8a:a8:d8:e2:b0:96:9e:56:39:40:c5:64:bf:fb:b2:
         b8:cb:e1:29:24:a7:ce:00:34:d6:a9:11:c4:bf:8e:ae:c8:5c:
         50:38:42:b9:15:9e:db:6b:00:ff:93:e8:0a:d3:00:13:0a:31:
         3b:cc:93:ad:92:09:9d:97:dd:42:28:07:43:91:39:86:2e:54:
         97:4a:a6:57:96:07:69:90:62:58:eb:0b:39:44:05:74:ad:f5:
         bc:6a:41:5e:79:dd:27:99:32:67:c3:82:14:df:4b:44:a9:7e:
         63:29:4e:c3:a3:ef:fa:1d:14:da:54:77:fb:6c:d8:c6:cc:5f:
         99:06:38:f0:2c:78:41:f7:a1:5a:d6:29:1d:5f:df:f9:3b:7b:
         cf:9f:73:f3:6c:b4:cf:0b:8e:39:7a:f1:35:3e:8d:66:12:4f:
         f4:b1:04:6c:1f:d6:27:75:91:43:82:a4:74:a8:77:84:f9:ca:
         14:71:8a:ac:da:3b:39:2d

有人能帮我解决这个问题吗?我知道我可以用主机名来解决,但我也想让它以这种方式工作


有关Spring Boot RestTemplate,请参见https://dev59.com/8GIk5IYBdhLWcg3wJ7L4#59317106。 - Grigory Kislin
1
我在Docker中遇到了这个问题,因为IP地址会随机分配给容器。有没有人对这种情况有解决方案? - Flavio Oliva
9个回答

12
这种失败的原因是目标终端点的主机名和证书中的公共名称 (CN 在证书 Subject 中) 不匹配。
例如,从 JVM 连接到 IP 地址 (WW.XX.YY.ZZ) 而非 DNS 名称 (https://stackoverflow.com),HTTPS 连接将失败,因为存储在 Java 信任库 cacerts 中的证书希望公共名称与目标地址相匹配。
为了解决这个问题,需要使用 HostnameVerifier 验证连接,尽管存在不匹配。参考链接:https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#HostnameVerifier
    HttpsURLConnection urlConnection = (HttpsURLConnection) new URL("https://test.test/api").openConnection();
    urlConnection.setSSLSocketFactory(buildSocketFactory());
    urlConnection.setDoOutput(true);
    urlConnection.setRequestMethod("get");
    urlConnection.setHostnameVerifier(new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession sslSession) {
            return true;
        }
    });
    urlConnection.getOutputStream();

5
buildSocketFactory() 的价值是什么? - Edijae Crusar

11

1
请问您能详细说明一下,我应该在哪里添加key=7吗?谢谢! - Prasannjeet Singh

4
我们之所以出现上述错误,是因为您证书中定义的CN(通用名称)与应用程序运行的域名不匹配。 例如,在您的证书中,CN名称定义为www.example.com或IP,但您可能正在运行类似于http://localhost:8080/api的URL的应用程序。
因此,要解决上述错误,只需使用以下方法之一:
在与证书中定义的“CN”相同的位置运行应用程序。
或者,
除CN名称外,您还可以在证书中添加主题备用名称,这类似于在证书中添加多个域。下面的链接描述了向jks文件和证书中添加多个域(subject-alt-name)的过程。
请参阅此链接:学习如何添加主题备用名称并解决上述错误

1
我遇到了同样的问题,现在分享我的经验。这些值应该是相同的。
将证书的CN值保存到/etc/hosts中,并尝试使用此URI访问它。它会起作用。 enter image description here

0
  1. 使用keytool(Java)导入.cert文件:
- listar: keytool -list -v -keystore cacerts
- importar: keytool -importcert -file your-cert.crt -keystore cacerts -alias "ldap cert"
  1. 请确认 JAVA_HOME 与运行代码时使用的 keytool 相同

  2. 在您的 .cert 文件中,主机名或域名必须与服务器域名相等

  3. 您必须使用工具验证证书是否有效,并确认 .cert 文件名称,例如,在 Windows 中可以使用以下命令:

    - CheckSSLCert.exe 您的服务器 IP [端口]

  4. 代码如下:

public DirContext dirContext(String currentPassword, String distinguishedName) throws Exception {
        log.info("getConnection configuration");
        try {
            Hashtable<String, String> env = new Hashtable<>();
            String keystore = System.getProperty("java.home") + System.getProperty("file.separator") + "lib" + System.getProperty("file.separator") + "security" + System.getProperty("file.separator") + "cacerts";
            System.setProperty("javax.net.ssl.trustStore", keystore);
            env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
            env.put(Context.PROVIDER_URL, "ldaps://yourserverldap.hostname:636");
            env.put(Context.SECURITY_AUTHENTICATION, "simple");
            env.put(Context.SECURITY_PRINCIPAL, "your ldap user");
            env.put(Context.SECURITY_CREDENTIALS, "your pass");
            env.put(Context.SECURITY_PROTOCOL, "ssl");
            return new InitialDirContext(env);
        } catch (Exception e) {
            log.info("error " + e.getMessage());
            throw e;
        }
    }

0
我在通过IP地址访问API时遇到了同样的问题。 所以,如果你和我一样处于无法对代码或证书本身进行太多更改的位置,那么你可以简单地在你的主机文件中添加CN名称。 所以在Windows操作系统中,我编辑了以下文件。
C:\Windows\System32\drivers\etc\hosts

并在其中添加了以下条目
10.10.10.10    xyz.domain.com

在证书的CN中,可以通过在浏览器中输入IP地址来找到域名。 enter image description here

如果CN名称类似于*.domain.com,那么您可以根据自己的方便设置域名,例如abc.domain.com

但是根据我的意见,这只应该用于本地测试。生产环境应该使用正确的域名地址,而不是IP地址。


0

执行以下步骤

1- 修改文件:/etc/ssl/openssl.cnf,例如:

subjectAltName=DNS:api.electoralsystem

2- 生成私钥

jmendoza@jmendoza:~$ openssl genrsa -aes256 -out electoralsystem-cakey.pem 2048 -alias electoralsystem-cakey.pem
Generating RSA private key, 2048 bit long modulus
....................+++++
.......................................+++++
e is 65537 (0x010001)
Enter pass phrase for electoralsystem-cakey.pem:
Verifying - Enter pass phrase for electoralsystem-cakey.pem:

3- 生成 cacert x509

jmendoza@jmendoza:~$ openssl req -new -x509 -sha256 -key electoralsystem-cakey.pem -days 365 -out electoralsystem-cacert.pem 
Enter pass phrase for electoralsystem-cakey.pem:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:VE
State or Province Name (full name) [Some-State]:CARACAS
Locality Name (eg, city) []:CARACAS
Organization Name (eg, company) [Internet Widgits Pty Ltd]:JMENDOZA
Organizational Unit Name (eg, section) []:TI
Common Name (e.g. server FQDN or YOUR name) []:api.electoralsystem
Email Address []:xxxx@gmail.com 

openssl x509 -in electoralsystem-cacert.pem -text

4- 生成 keystore pkcs12

jmendoza@jmendoza:~$ openssl pkcs12 -export -in electoralsystem-cacert.pem -inkey electoralsystem-cakey.pem -out electoralsystem-store.p12 -name "electoralsystem-store" 
Enter pass phrase for electoralsystem-cakey.pem:
Enter Export Password:
Verifying - Enter Export Password:

5- 如果需要,可以使用keytool命令将PKCS12密钥库转换为JKS密钥库

jmendoza@jmendoza:~$ keytool -importkeystore -destkeystore electoralsystem-store.jks -deststorepass jmendoza -srckeystore electoralsystem-store.p12 -srcstoretype PKCS12 -srcstorepass jmendoza -alias electoralsystem-store
Importando el almacén de claves de electoralsystem-store.p12 a electoralsystem-store.jks...

6- 在客户端中,将证书导入密钥库

jmendoza@jmendoza:~$ keytool -importcert -file electoralsystem-cacert.pem -keystore ldap-server-smmt.jks 
Introduzca la contraseña del almacén de claves:

在密钥库中导入证书

调用API - https://api.electoralsystem:8081/yyyy/xxxxx

7- 在API服务器上配置证书

在API服务器上配置证书

8- 生成文件摘要

jmendoza@jmendoza:~$ ls -lt
total 1332
-rw-rw-r--  1 jmendoza jmendoza    2482 jul 25 10:15  ldap-server-smmt.jks
-rw-r--r--  1 jmendoza jmendoza    2442 jul 25 10:04  electoralsystem-store.jks
-rw-------  1 jmendoza jmendoza    2792 jul 25 10:01  electoralsystem-store.p12
-rw-r--r--  1 jmendoza jmendoza    1509 jul 25 09:45  electoralsystem-cacert.pem
-rw-------  1 jmendoza jmendoza    1766 jul 25 09:38  electoralsystem-cakey.pem

注意:在客户端的docker或服务器上配置DNS api.electoralsystem。

0

我已经解决了以下问题:

javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative names matching IP address

通过在服务器证书(CN=example.com)中添加一个备用主题名称(DNS),解决了错误,并打印了证书的部分内容如下:

Subject Alternative Name:
DNS: example.com

我在Windows上使用KeyExplorer生成了我的服务器证书。您可以按照此链接添加替代主题名称(只需按照添加部分即可)。


-1

不要使用 IP 地址作为您的 URL。 您可以尝试在 URL 中使用 FQDN。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接