Решение javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed Ошибка?
Редактировать: - Попытался отформатировать вопрос и принял ответ более презентабельным способом в моем блоге
Вот оригинальная проблема.
Я получаю эту ошибку:
подробное сообщение sun.security.validator.ValidatorException: не удалось построить путь PKIX:
sun.security.provider.certpath.SunCertPathBuilderException: невозможно найти действительный путь сертификации к запрошенной цели
причиной javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: сбой построения пути PKIX: sun.security.provider.certpath.SunCertPathBuilderException: невозможно найти действительный путь сертификации для запрошенной цели
Я использую Tomcat 6 в качестве веб-сервера. У меня есть два веб-приложения HTTPS, установленные на разных Tomcats на разных портах, но на одной машине. Скажите App1(port 8443)
и App2(port 443)
. App1
подключается к App2
. Когда App1
подключается к App2
я получаю вышеуказанную ошибку. Я знаю, что это очень распространенная ошибка, поэтому сталкивался со многими решениями на разных форумах и сайтах. У меня есть запись ниже в server.xml
обоих Tomcats:
keystoreFile="c:/.keystore"
keystorePass="changeit"
На каждом сайте указана одна и та же причина, по которой сертификат, предоставленный app2, отсутствует в доверенном хранилище app1 jvm. Кажется, это также верно, когда я пытался перейти по тому же URL-адресу в браузере IE, он работает (с потеплением. Существует проблема с этим сертификатом безопасности веб-сайта. Здесь я говорю, перейдите на этот веб-сайт). Но когда Java-клиент использует тот же URL-адрес (в моем случае), я получаю вышеуказанную ошибку. Поэтому, чтобы положить его в доверенное хранилище, я попробовал эти три варианта:
Опция 1
System.setProperty("javax.net.ssl.trustStore", "C:/.keystore");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
Option2 Настройка ниже в переменной среды
CATALINA_OPTS -- param name
-Djavax.net.ssl.trustStore=C:\.keystore -Djavax.net.ssl.trustStorePassword=changeit ---param value
Option3 Настройка ниже в переменной среды
JAVA_OPTS -- param name
-Djavax.net.ssl.trustStore=C:\.keystore -Djavax.net.ssl.trustStorePassword=changeit ---param value
Но ничего не сработало.
Наконец, сработало выполнение подхода Java, предложенного в разделе Как обрабатывать недействительные сертификаты SSL с помощью Apache HttpClient? по Паскалю Thivent, т.е. выполнение программы InstallCert.
Но этот подход хорош для установки devbox, но я не могу использовать его в производственной среде.
Мне интересно, почему три упомянутых выше подхода не сработали, когда я упомянул одинаковые значения в server.xml
сервера app2
и одинаковые значения в хранилище доверенных сертификатов, установив
System.setProperty("javax.net.ssl.trustStore", "C:/.keystore") and System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
в программе app1
.
Для получения дополнительной информации вот как я делаю соединение:
URL url = new URL(urlStr);
URLConnection conn = url.openConnection();
if (conn instanceof HttpsURLConnection) {
HttpsURLConnection conn1 = (HttpsURLConnection) url.openConnection();
conn1.setHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
reply.load(conn1.getInputStream());
Ответы
Ответ 1
Вам необходимо добавить сертификат для App2 в файл хранилища доверенных сертификатов используемой JVM, расположенный по адресу %JAVA_HOME%\lib\security\cacerts
.
Сначала вы можете проверить, находится ли ваш сертификат в хранилище доверенных сертификатов, выполнив следующую команду: keytool -list -keystore "%JAVA_HOME%/jre/lib/security/cacerts"
(вам не нужно keytool -list -keystore "%JAVA_HOME%/jre/lib/security/cacerts"
пароль)
Если ваш сертификат отсутствует, вы можете получить его, загрузив его в браузере и добавив в доверенное хранилище с помощью следующей команды:
keytool -import -noprompt -trustcacerts -alias <AliasName> -file <certificate> -keystore <KeystoreFile> -storepass <Password>
После импорта вы можете снова запустить первую команду, чтобы проверить, был ли добавлен ваш сертификат.
Информация Sun/Oracle может быть найдена здесь.
Ответ 2
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: Не удалось создать путь PKIX: sun.security.provider.certpath.SunCertPathBuilderException: не удалось найти допустимый путь сертификации для запрошенной цели
• Когда я получил сообщение об ошибке, я попытался выяснить значение выражения в Google, и я обнаружил, что эта проблема возникает, когда сервер изменяет свой SSL-сертификат HTTPS, а наша более ранняя версия java не распознает корневой центр сертификации (CA).
• Если вы можете получить доступ к URL-адресу HTTPS в своем браузере, тогда можно обновить Java для распознавания корневого ЦС.
• В своем браузере перейдите к URL-адресу HTTPS, к которому Java не может получить доступ. Нажмите на цепочку сертификатов HTTPS (в Internet Explorer есть значок блокировки), щелкните по блокировке, чтобы просмотреть сертификат.
• Перейдите к "Подробности" сертификата и "Скопируйте в файл". Скопируйте его в формате Base64 (.cer). Он будет сохранен на вашем рабочем столе.
• Установите сертификат, игнорируя все предупреждения.
• Вот как я собрал информацию о сертификате URL-адреса, к которому я пытался получить доступ.
Теперь мне нужно было сделать мою версию Java, чтобы узнать о сертификате, чтобы в дальнейшем он не отказался распознавать URL. В этом отношении я должен упомянуть, что я искал информацию о корневом сертификате по умолчанию в JDKs \jre\lib\security, а пароль для доступа по умолчанию: changeit.
Чтобы просмотреть информацию о cacerts, выполните следующие действия:
• Нажмите кнопку "Пуск" → "Выполнить"
• Введите cmd. Откроется командная строка (возможно, вам нужно будет открыть ее как администратор).
• Перейдите в каталог Java/jreX/bin
• Введите следующий
keytool -list -keystore D:\Java\jdk1.5.0_12\jre\lib\security\cacerts
Он дает список текущих сертификатов, содержащихся в хранилище ключей. Это выглядит примерно так:
C:\Documents and Settings\NeelanjanaG > keytool -list -keystore D:\Java\jdk1.5.0_12\jre\lib\security\cacerts
Введите пароль хранилища ключей: changeit
Тип хранилища: jks
Поставщик ключей: SUN
Ваше хранилище ключей содержит 44 записи
verisignclass3g2ca, 26 марта 2004 г., trustedCertEntry,
Отпечаток сертификата (MD5): A2: 33: 9B: 4C: 74: 78: 73: D4: 6C: E7: C1: F3: 8D: CB: 5C: E9
entrustclientca, 9 января 2003 г., trustedCertEntry,
Отпечаток сертификата (MD5): 0C: 41: 2F: 13: 5B: A0: 54: F5: 96: 66: 2D: 7E: CD: 0E: 03: F4
thawtepersonalbasicca, 13 февраля 1999 г., trustedCertEntry,
Отпечаток сертификата (MD5): E6: 0B: D2: C9: CA: 2D: 88: DB: 1A: 71: 0E: 4B: 78: EB: 02: 41
addtrustclass1ca, 1 мая 2006 г., trustedCertEntry,
Отпечаток сертификата (MD5): 1E: 42: 95: 02: 33: 92: 6B: B9: 5F: C0: 7F: DA: D6: B2: 4B: FC
verisignclass2g3ca, 26 марта 2004 г., trustedCertEntry,
Отпечаток сертификата (MD5): F8: BE: C4: 63: 22: C9: A8: 46: 74: 8B: B8: 1D: 1E: 4A: 2B: F6
• Теперь мне пришлось включить ранее установленный сертификат в cacerts.
• Для этого выполняется процедура:
keytool -import -noprompt -trustcacerts -alias ALIASNAME файл FILENAME_OF_THE_INSTALLED_CERTIFICATE -keystore PATH_TO_CACERTS_FILE -storepass PASSWORD
Если вы используете Java 7:
keytool -importcert -trustcacerts -alias ALIASNAME файл PATH_TO_FILENAME_OF_THE_INSTALLED_CERTIFICATE -keystore PATH_TO_CACERTS_FILE -storepass changeit
• Затем он добавит информацию сертификата в файл cacert.
Это решение, которое я нашел для вышеупомянутого исключения!
Ответ 3
Как работать - в Tomcat 7
Я хотел поддержать самоподписанный сертификат в приложении Tomcat, но не удалось выполнить следующий сниппет
import java.io.DataOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class HTTPSPlayground {
public static void main(String[] args) throws Exception {
URL url = new URL("https:// ... .com");
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
httpURLConnection.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(httpURLConnection.getOutputStream());
String serializedMessage = "{}";
wr.writeBytes(serializedMessage);
wr.flush();
wr.close();
int responseCode = httpURLConnection.getResponseCode();
System.out.println(responseCode);
}
}
вот что решило мою проблему:
1) Загрузите .crt
файл
echo -n | openssl s_client -connect <your domain>:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ~/<your domain>.crt
- замените
<your domain>
на свой домен (например, jossef.com
)
2) Примените файл .crt
в хранилище сертификатов Java cacerts
keytool -import -v -trustcacerts -alias <your domain> -file ~/<your domain>.crt -keystore <JAVA HOME>/jre/lib/security/cacerts -keypass changeit -storepass changeit
- замените
<your domain>
на свой домен (например, jossef.com
)
- замените
<JAVA HOME>
на ваш домашний каталог java
3) Взломайте его
Даже если я установил свой сертификат в хранилища сертификатов Java
по умолчанию, Tomcat игнорирует этот (похоже, он не настроен на использование хранилищ сертификатов по умолчанию Java).
Чтобы взломать это, добавьте следующее в код:
String certificatesTrustStorePath = "<JAVA HOME>/jre/lib/security/cacerts";
System.setProperty("javax.net.ssl.trustStore", certificatesTrustStorePath);
// ...
Ответ 4
В моем случае проблема заключалась в том, что веб-сервер отправлял только сертификат и промежуточный ЦС, а не корневой ЦС. Добавление этой опции JVM решило проблему: -Dcom.sun.security.enableAIAcaIssuers=true
Доступна поддержка метода доступа caIssuers расширения Authority Information Access. По умолчанию он отключен для совместимости и может быть включен путем установки системному свойству com.sun.security.enableAIAcaIssuers
значения true.
Если задано значение true, реализация CertPathBuilder в Sun PKIX использует информацию в расширении AIA сертификата (в дополнение к указанному CertStores) для поиска сертификата выдающего ЦС при условии, что это URI типа ldap, http или ftp.
Источник
Ответ 5
Другой причиной может быть устаревшая версия JDK. Я использовал jdk версии 1.8.0_60, просто обновление до последней версии решило проблему с сертификатом.
Ответ 6
Мой файл cacerts был полностью пуст. Я решил это, скопировав файл cacerts с моей машины Windows (используя Oracle Java 7) и scp'd в мой Linux-блок (OpenJDK).
cd %JAVA_HOME%/jre/lib/security/
scp cacerts mylinuxmachin:/tmp
а затем на машине linux
cp /tmp/cacerts /etc/ssl/certs/java/cacerts
До сих пор он отлично работал.
Ответ 7
Используя Tomcat 7 под Linux, это сделало трюк.
String certificatesTrustStorePath = "/etc/alternatives/jre/lib/security/cacerts";
System.setProperty("javax.net.ssl.trustStore", certificatesTrustStorePath);
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
В Linux $JAVA_HOME
не всегда настроен, но обычно /etc/alternatives/jre
указывает на $JAVA_HOME/jre
Ответ 8
Ниже код работает для меня:
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;
public class TrustAnyTrustManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[] {};
}
}
HttpsURLConnection conn = null;
URL url = new URL(serviceUrl);
conn = (HttpsURLConnection) url.openConnection();
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom());
conn.setSSLSocketFactory(sc.getSocketFactory());
Ответ 9
Для меня эта ошибка также возникла при попытке подключиться к процессу с обратным прокси-сервером NGINX, который обрабатывал SSL.
Оказалось, что проблема связана с сертификатом без конкатенации всей цепочки сертификатов.
Когда я добавил промежуточные сертификаты, проблема была решена.
Надеюсь, что это поможет.
Ответ 10
Я использовал jdk1.8.0_171
когда столкнулся с той же проблемой. Я попробовал два лучших решения здесь (добавление сертификата с помощью keytool и другого решения, в котором есть хак), но они не спомогли мне.
Я обновил свой JDK до 1.8.0_181
и он работал, как шарм.
Ответ 11
Я написал небольшой win32 (WinXP 32bit testet) stupid cmd (commandline) script, который ищет все версии java в файлах программ и добавляет к ним сертификат.
Пароль должен быть по умолчанию "changeit" или изменить его самостоятельно в script: -)
@echo off
for /F %%d in ('dir /B %ProgramFiles%\java') do (
%ProgramFiles%\Java\%%d\bin\keytool.exe -import -noprompt -trustcacerts -file some-exported-cert-saved-as.crt -keystore %ProgramFiles%\Java\%%d\lib\security\cacerts -storepass changeit
)
pause
Ответ 12
Для Tomcat, работающего на сервере Ubuntu, чтобы узнать, какая Java используется, используйте команду "ps -ef | grep tomcat":
Пример:
/home/mcp01$ **ps -ef |grep tomcat**
tomcat7 28477 1 0 10:59 ? 00:00:18 **/usr/local/java/jdk1.7.0_15/bin/java** -Djava.util.logging.config.file=/var/lib/tomcat7/conf/logging.properties -Djava.awt.headless=true -Xmx512m -XX:+UseConcMarkSweepGC -Djava.net.preferIPv4Stack=true -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/usr/share/tomcat7/endorsed -classpath /usr/share/tomcat7/bin/bootstrap.jar:/usr/share/tomcat7/bin/tomcat-juli.jar -Dcatalina.base=/var/lib/tomcat7 -Dcatalina.home=/usr/share/tomcat7 -Djava.io.tmpdir=/tmp/tomcat7-tomcat7-tmp org.apache.catalina.startup.Bootstrap start
1005 28567 28131 0 11:34 pts/1 00:00:00 grep --color=auto tomcat
Затем мы можем перейти к: cd/usr/local/java/jdk1.7.0_15/jre/lib/security
Файл cacerts находится здесь. Вставьте в него ненадежный сертификат.
Ответ 13
У меня тоже есть эта проблема.
Я попробовал почти все, добавив SSL-сертификат в .keystore, но он не работал с Java1_6_x.
Для меня это помогло, если мы начнем использовать более новую версию Java, Java1_8_x как JVM.
Ответ 14
для безопасности мы не должны использовать самозаверяющие сертификаты в нашей реализации. Тем не менее, когда речь заходит о разработке, нам часто приходится использовать пробные среды с самоподписанными сертификатами. Я попытался исправить эту проблему программно в моем коде, и мне это не удалось. Однако добавление сертификата в jre trust-store решило мою проблему. Пожалуйста, найдите ниже шаги,
-
Скачать сайт сертификата,
-
Скопируйте сертификат (например, cert_file.cer) в каталог $ JAVA_HOME\Jre\Lib\Security
-
Откройте CMD в Администраторе и измените каталог на $ JAVA_HOME\Jre\Lib\Security
-
Импортируйте сертификат в доверенное хранилище, используя следующую команду:
keytool -import -alias ca -file cert_file.cer -keystore cacerts -storepass changeit
Если вы получили сообщение о том, что keytool не распознается, обратитесь к этому.
Тип да как ниже
Доверяйте этому сертификату: [Да]
- Теперь попробуйте запустить свой код или получить доступ к URL программно с помощью Java.
Обновить
Если ваш сервер приложений jboss, попробуйте добавить системное свойство ниже
System.setProperty("org.jboss.security.ignoreHttpsHost","true");
Надеюсь это поможет!
Ответ 15
Я столкнулся с этой проблемой, используя AndroidStudio
, Charles Proxy
, JUnit
и Robolectric
.
Спасибо @SimonSez, я смог решить проблему.
Обратите внимание: Поскольку ключевым моментом является изменение cacerts
, которое может вызвать некоторые проблемы (например, обновление IDE), я бы порекомендовал вам скопировать исходный файл cacerts
в отдельный файл. каталог и манипулировать ими при необходимости.
%JAVA_HOME%
- Android использует другой JavaHome. Вы можете найти полный путь на вкладке UnitTests resulr
. В моем случае это /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home
![enter image description here]()
Загрузить сертификат Чарльза (например, папка Downloads
)
Запустите команду
sudo keytool -import -noprompt -trustcacerts -alias charles -file <path to Charles certificate.pem> -keystore "JAVA_HOME/jre/lib/security/cacerts" -storepass changeit
Например,
sudo keytool -import -noprompt -trustcacerts -alias charles -file ~/Downloads/charles-ssl-proxying-certificate.pem -keystore "/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/jre/lib/security/cacerts" -storepass changeit
Официальный Чарльз Док
Ответ 16
Для MacOS X ниже точная команда работала для меня, где я должен был попробовать с двойным hypen в опции importcert, которая работала:
sudo keytool -–importcert -file /PathTo/YourCertFileDownloadedFromBrowserLockIcon.crt -keystore /Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home/jre/lib/security/cacerts -alias "Cert" -storepass changeit
Ответ 17
У меня была эта проблема с Android Studio, когда я за прокси. Я использовал Crashlytics, который пытается загрузить файл сопоставления во время сборки.
Я добавил недостающий сертификат прокси в склад доверенных сертификатов, расположенный по адресу
/Users/[username]/Documents/Android Studio.app/Contents/jre/jdk/Contents/Home/jre/lib/security/cacerts
с помощью следующей команды: keytool -import -trustcacerts -keystore cacerts -storepass [password] -noprompt -alias [alias] -file [my_certificate_location]
например, с паролем хранилища доверенных сертификатов по умолчанию
keytool -import -trustcacerts -keystore cacerts -storepass changeit -noprompt -alias myproxycert -file /Users/myname/Downloads/MyProxy.crt
Ответ 18
добавьте это в свой код:
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (GeneralSecurityException e) {
}
Ответ 19
Его недостаток Java не использует стандартное хранилище ключей операционной системы, как в MacOS X. Я подал заявку на изменение сегодня, см. http://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8185892