JDK 11 HttpClient выдает ошибку альтернативного имени DNS без субъекта

Я пишу простой клиент API REST на основе JDK11 HttpClient, простой код, как показано ниже:

public class MyClass {

    private static final X509TrustManager TRUST_MANAGER = new X509TrustManager() {
        public void checkClientTrusted(X509Certificate[] xcs, String string) {
        }

        public void checkServerTrusted(X509Certificate[] xcs, String string) {
        }

        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    };

    private static HttpClient getNewHttpClient() {
        int timeout = 600;
        try {

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

            SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
            sslContext.init(null, new TrustManager[]{TRUST_MANAGER}, new SecureRandom());

            // Install the all-trusting host verifier
            HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());

            //Set SSL parameters
            SSLParameters parameters = new SSLParameters();
            parameters.setEndpointIdentificationAlgorithm("HTTPS");
                HttpClient httpClient = HttpClient.newBuilder()
                    .connectTimeout(Duration.ofMillis(timeout * 1000))
                    .sslContext(sslContext)
                    .sslParameters(parameters)
                    .build();
            return httpClient;
        } catch (Exception e) {
            logger.warn("Unable to create HttpClient with disabled SSL Certificate verifying, default client will be used", e);
            return HttpClient.newHttpClient();
        }
    }

    public static void main(String[] args) {
        HttpRequest requestBuilder = HttpRequest.newBuilder()
                .uri(URI.create("https://somehostname.xx.xxx.net"))
                .GET()
                .build();

        getNewHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
    }
}

Проблема в том, что когда я пытаюсь открыть какой-либо домен SSL, я получаю сообщение об ошибке:

Причина: java.security.cert.CertificateException: не найдено альтернативное DNS-имя субъекта, соответствующее somehostname.xx.xxx.net.

Как я могу решить эту проблему?


person Andrey    schedule 17.10.2018    source источник
comment
изучил stackoverflow.com/questions/19540289/ ?   -  person Naman    schedule 17.10.2018
comment
Да. Но мне это не помогает. Как видите, я попытался отключить проверку, добавив HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true); но это не влияет на HttpClient из JDK11.   -  person Andrey    schedule 18.10.2018
comment
@ Андрей Сталкиваетесь ли вы с той же проблемой, используя JDK ‹ 11? Можете ли вы предоставить общедоступное имя хоста для тестирования?   -  person Mikhail Kholodkov    schedule 18.10.2018
comment
Отключение проверки имени хоста никогда не будет хорошей идеей — это сделает ваше соединение небезопасным. Что произойдет, если вы введете URL-адрес в веб-браузере? Браузер принимает сервер или показывает ошибку? Если он показывает ошибку, это проблема на стороне сервера/сертификата сервера, а не проблема клиента/Java.   -  person Robert    schedule 20.10.2018
comment
@Андрей, каков конкретный вариант использования? Почему имя хоста сервера, к которому вы подключаетесь, не соответствует CN или SAN в его сертификате? Если это всего лишь тестовая среда, проверку имени хоста можно отключить с помощью -Djdk.internal.httpclient.disableHostnameVerification на свой страх и риск.   -  person chegar999    schedule 23.10.2018
comment
программно отключить проверку имени хоста перед созданием экземпляра httpclient // PREVENTS HOST VALIDATION final Properties props = System.getProperties(); props.setProperty("jdk.internal.httpclient.disableHostnameVerification", Boolean.TRUE.toString());   -  person liltitus27    schedule 16.11.2018
comment
@ liltitus27, а теперь представьте, что у вас есть два клиента: одному нужно отключить это свойство, а другому — включить. :(   -  person Eugene    schedule 18.08.2020


Ответы (1)


Хотя полное отключение проверки имени хоста (т. е. для всей виртуальной машины) может быть опцией, это может быть опасно. Вы также можете отключить проверку имени хоста, если вы получаете TRUST_MANAGER от javax.net.ssl.X509ExtendedTrustManager.

    private static final TrustManager DUMMY_TRUST_MANAGER = new X509ExtendedTrustManager() {        
    @Override
    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return new java.security.cert.X509Certificate[0];
    }
    @Override
    public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { }
    @Override
    public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { }
    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine) throws CertificateException { }
    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException { }
    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine) throws CertificateException { }
    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException { }
};

Конечно, это также полностью отключит любые проверки сертификатов, представленных вашему клиенту.

Существует также открытый вопрос по адресу https://bugs.openjdk.java.net/browse/JDK-8213309, чтобы добавить в JDK API для отключения проверки имени хоста. Если у вас есть доступ к базе данных ошибок openjdk, вы можете проголосовать за проблему.

person rli    schedule 21.05.2021
comment
Это работает для меня. Не могли бы вы немного объяснить эту функцию, пожалуйста? Кстати, спасибо за это решение! - person clauub; 25.06.2021