Я пытаюсь сделать HTTPS-запрос от клиента Java 8 (используя Apache HttpClient 4.3) к общедоступному серверу (которым я не владею). Обычно у меня никогда не было проблем с запросами, но целевой сервер, похоже, внес некоторые изменения, и запросы начали давать сбой.
Первоначально ошибка была ValidatorException: PKIX Path Building Failed
, но я исправил это, добавив сертификат сервера в мое хранилище доверенных сертификатов Java. Теперь я получаю ошибку hostname in certificate didn't match: <target.server.com> != <*.something.else.com> OR <something.else.com>
.
Хост something.else.com
- это своего рода хостинг и т. Д. В любом случае, я уверен, что в этом нет ничего подозрительного. Я вытащил сертификат для target.server.com
, выполнив следующую команду:
openssl s_client -connect target.server.com:443 -showcerts
Я не вижу никакой ссылки на target.server.com
в информации о сертификате, только для something.else.com
. У меня нет проблем с посещением target.server.com
в веб-браузере (Chrome), и нет никаких претензий к сертификату SSL. Я добавил сертификат сервера в хранилище доверенных сертификатов с помощью этой команды:
sudo keytool -import -file /tmp/target.cer -keystore /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/security/cacerts -alias targetserv
Есть ли способ исправить это без изменения кода Java, например добавить что-то в команду импорта сертификата и т. д., а если нет, как еще можно заставить эти запросы работать снова.
Вот мой код HTTP-запроса (с использованием HttpClient 4.3):
CloseableHttpClient httpClient = HttpClients.custom().setUserAgent(HTTP_USER_AGENT).build();
HttpGet request = new HttpGet(url);
HttpResponse response = httpClient.execute(request);
... бросает java.io.IOException: hostname in certificate didn't match
Кроме того, это фактический целевой сервер, к которому я пытаюсь связаться: https://www.isi.gov.ie
Я пытался использовать HttpClient v4.5, и все равно получаю ту же ошибку, что и в 4.3. Я попытался сделать запрос, используя встроенные в Java классы HTTP-запросов, и запрос успешно выполнен (возвращается 302):
URL obj = new URL("https://www.isi.gov.ie");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", USER_AGENT);
int responseCode = con.getResponseCode();
System.out.println("\nSending 'GET' request to URL : " + url);
System.out.println("Response Code : " + responseCode);
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
//print result
System.out.println(response.toString());
Можно ли как-нибудь исправить эти проблемы с помощью HttpClient?
Оказывается, в другом месте моего приложения я отключал SNI с помощью системного свойства Java jsse.enableSNIExtension
и забыл об этом. Причина, по которой я это делал, заключается в том, что это было единственное исправление, которое я смог найти, чтобы предотвратить ВСЕ HTTP-запросы, использующие HttpClient, с ошибкой:
sun.security.validator.ValidatorException: сбой построения пути PKIX: sun.security.provider.certpath.SunCertPathBuilderException: невозможно найти действительный путь сертификации для запрошенной цели
Как я могу снова включить SNI без этих ошибок?
Я использую следующую версию Java:
openjdk version "1.8.0_212"
OpenJDK Runtime Environment (build 1.8.0_212-8u212-b03-0ubuntu1.18.04.1-b03)
OpenJDK 64-Bit Server VM (build 25.212-b03, mixed mode)