Подтвердить что ты не робот

CertificateException: не найдено совпадений с именем ssl.someUrl.de

Я пытаюсь подключиться к одному из моих серверов через ssl с помощью Java. Я попробовал много вариантов, вот моя лучшая попытка:

Я генерирую jssecacerts с рекомендацией script: 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()));

И я получаю сообщение об ошибке на третьей строке: (Не найдено совпадения имен 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

4b9b3361

Ответ 1

Похоже, что сертификат сервера, к которому вы пытаетесь подключиться, не соответствует его имени хоста.

Когда клиент HTTPS подключается к серверу, он проверяет, что имя хоста в сертификате совпадает с именем хоста сервера. Недостаточно доверять сертификату, он должен соответствовать серверу, с которым вы хотите поговорить. (В качестве аналогии, даже если вы доверяете паспорту, чтобы быть законным, вам все равно нужно проверить, что это для человека, с которым вы хотите поговорить, а не только для любого паспорта, которому вы доверяете, чтобы быть законным.)

В HTTP это делается, проверяя, что:

  • сертификат содержит альтернативное имя объекта DNS (это стандартное расширение), соответствующее имени хоста;

  • В противном случае последний CN вашего выделенного имени объекта (это главное имя, если хотите) соответствует имени хоста. (См. RFC 2818.)

Трудно сказать, что альтернативное имя субъекта не имеет сертификата (хотя, если вы подключаетесь к своему браузеру и проверяете его содержимое более подробно, вы должны его увидеть). Субъект различного имени выглядит следующим образом:

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

(Таким образом, для CN = ssl.someUrl.de вместо CN = plesk, если у вас нет альтернативного имени объекта с DNS: ssl.someUrl.de уже, я полагаю, т.)

Вы можете обойти проверку имени хоста, используя HttpsURLConnection.setHostnameVerifier(..). Не должно быть слишком сложно написать собственный HostnameVerifier, который проверяет проверку, хотя я бы предложил сделать это только тогда, когда сертификат его касается именно здесь. Вы должны иметь возможность получить это с помощью аргумента SSLSession и метода getPeerCertificates().

(Кроме того, вам не нужно устанавливать свойства javax.net.ssl. * так, как вы это делали, поскольку вы все равно используете значения по умолчанию.)

В качестве альтернативы, если у вас есть контроль над подключаемым сервером и его сертификатом, вы можете создать его сертификат, соответствующий правилам именования выше (CN должно быть достаточным, хотя альтернативное имя объекта является улучшением). Если самозаверяющий сертификат достаточно хорош для того, что вы называете, убедитесь, что его общее имя (CN) - это имя хоста, с которым вы пытаетесь поговорить (нет полного URL-адреса, просто имя хоста).

Ответ 2

В Java 8 вы можете пропустить проверку имени сервера с помощью следующего кода:

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

Однако это должно использоваться только в разработке!

Ответ 3

Я создал метод fixUntrustCertificate(), поэтому, когда я имею дело с доменом, который не находится в доверенных ЦС, вы можете вызвать метод перед запросом. Этот код будет работать после 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/

Но моя проблема была немного иной и решила ее по-другому.

Веб-служба была на удаленном хосте. Например: https://some.remote.host/MyWebService?wsdl

Но он был доступен только по IP для любых клиентов, но для домена был создан сертификат: some.remote.host(CN = some.remote.host). И этот домен не может быть разрешен IP, потому что он не представлен в DNS).

Итак, возникла одна и та же проблема: если я использую IP для подключения к веб-сервису с помощью ssl, его невозможно достичь, поскольку сертификат CN = some.remote.host и не равен имени хоста, которое я указал (т.е. хост IP).

Я разрешил его, сопоставив это имя хоста с IP-адресом в файле /etc/hosts. Проблема была исправлена.

Но в случае, если веб-служба размещена на сервере приложений localhost, она думает, что она должна быть решена как mkyong, описанная в его статье.

Ответ 5

Имя сервера должно быть таким же, как имя/фамилия, которые вы указываете при создании сертификата