Как решить ошибку javax.net.ssl.SSLHandshakeException?
Я подключился к VPN для настройки API инвентаризации, чтобы получить список продуктов, и он работает нормально. Как только я получаю результат от веб-сервиса, и я привязываюсь к пользовательскому интерфейсу. А также я интегрировал PayPal с моим приложением для совершения экспресс-проверки, когда я делаю звонок для оплаты. Я столкнулся с этой ошибкой. Я использую сервлет для внутреннего процесса. Может ли кто-нибудь сказать, как исправить эту проблему?
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException:
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target
Ответы
Ответ 1
Во-первых, вам нужно получить публичный сертификат с сервера, к которому вы пытаетесь подключиться. Это можно сделать различными способами, например, связавшись с администратором сервера и запросив его, используя OpenSSL для его загрузки или, поскольку это HTTP-сервер, подключающийся к нему через любой браузер, просматривающий информацию о безопасности страницы. и сохранение копии сертификата. (Google должен быть в состоянии точно сказать вам, что делать для вашего конкретного браузера.)
Теперь, когда у вас есть сертификат, сохраненный в файле, вам нужно добавить его в ваше хранилище доверенных сертификатов JVM. В $JAVA_HOME/jre/lib/security/
для JRE или $JAVA_HOME/lib/security
для JDK есть файл cacerts
, который поставляется с Java и содержит публичные сертификаты известных сертифицирующих органов. Чтобы импортировать новый сертификат, запустите keytool от имени пользователя, имеющего разрешение на запись в cacerts:
keytool -import -file <the cert file> -alias <some meaningful name> -keystore <path to cacerts file>
Скорее всего, он попросит вас ввести пароль. Пароль по умолчанию, поставляемый с Java, это changeit
. Почти никто не меняет это. Выполнив эти относительно простые шаги, вы будете общаться безопасно и с уверенностью, что говорите с правильным сервером и только с нужным сервером (до тех пор, пока они не потеряют свой закрытый ключ).
Ответ 2
Теперь я решил эту проблему таким образом,
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.OutputStream;
// Create a trust manager that does not validate certificate chains like the default
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers()
{
return null;
}
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
{
//No need to implement.
}
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
{
//No need to implement.
}
}
};
// Install the all-trusting trust manager
try
{
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
catch (Exception e)
{
System.out.println(e);
}
Конечно, это решение должно использоваться только в сценариях, где невозможно установить требуемые сертификаты с помощью keytool
например. локальное тестирование с временными сертификатами.
Ответ 3
Всякий раз, когда мы пытаемся подключиться к URL-адресу,
если сервер на другом сайте работает по протоколу https и обязывает нас обмениваться информацией, предоставленной в сертификате, тогда мы имеем следующий вариант:
1) попросите сертификат (загрузить сертификат), импортируйте этот сертификат в trustore. По умолчанию для использования функции доверия по умолчанию java можно найти в \Java\jdk1.6.0_29\jre\lib\security\cacerts, тогда, если мы повторим попытку подключения к URL-соединению, будет принято.
2) В нормальных бизнес-ситуациях мы можем подключаться к внутренним URL-адресам в организациях, и мы знаем, что они верны. В таких случаях вы доверяете правильному URL-адресу. В таких случаях выше может использоваться код, который не будет иметь права хранить сертификат для подключения к определенному URL-адресу.
для точки № 2 мы должны следовать ниже:
1) напишите ниже метод, который устанавливает HostnameVerifier для HttpsURLConnection, который возвращает true для всех случаев, то есть мы доверяем trustStore.
// trusting all certificate
public void doTrustToCertificates() throws Exception {
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
return;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
return;
}
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String urlHostName, SSLSession session) {
if (!urlHostName.equalsIgnoreCase(session.getPeerHost())) {
System.out.println("Warning: URL host '" + urlHostName + "' is different to SSLSession host '" + session.getPeerHost() + "'.");
}
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(hv);
}
2) напишите ниже метод, который вызывает doTrustToCertificates перед попыткой подключения к URL
// connecting to URL
public void connectToUrl(){
doTrustToCertificates();//
URL url = new URL("https://www.example.com");
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
System.out.println("ResponseCode ="+conn.getResponseCode());
}
Этот вызов вернет код ответа = 200 означает успешное соединение.
Для более подробного и примерного примера вы можете обратиться к URL.
Ответ 4
Я считаю, что вы пытаетесь подключиться к чему-то, используя SSL, но что-то предоставляет сертификат, который не проверяется корневыми органами сертификации, такими как verisign. По сути, по умолчанию безопасные соединения могут быть установлены только в том случае, если человек, пытающийся для соединения знает ключи контрагентов или какой-либо другой верндор, такой как verisign, может вмешаться и сказать, что предоставленный публичный ключ действительно прав.
ВСЕ ОС доверяют нескольким органам сертификации и небольшим сертификатам сертификатов, которые должны быть сертифицированы одним из крупных сертификаторов, создающих цепочку сертификаторов, если вы понимаете, что я имею в виду...
В любом случае вернемся к делу. У меня была аналогичная проблема при программировании java-апплета и java-сервера (надеюсь, когда-нибудь я напишу полный блог-блог о том, как я получил всю безопасность для работы:))
В сущности, мне нужно было извлечь открытые ключи с сервера и сохранить их в хранилище ключей в моем апплете, и когда я подключился к серверу, я использовал этот хранилище ключей для создания доверия factory и что доверие factory, чтобы создать соединение ssl. Существуют также альтернативные процедуры, такие как добавление ключа к доверенному хосту JVM и изменение хранилища доверия по умолчанию при запуске.
Я сделал это примерно два месяца назад и не имею исходного кода для меня прямо сейчас.. используйте Google, и вы должны решить эту проблему. Если вы не можете передать мне сообщение, и я могу предоставить вам соответствующий исходный код для проекта. Не знаете, решает ли эта проблема вашу проблему, поскольку вы не предоставили код, который вызывает эти исключения. Кроме того, я работал с апплетами, я думал, что не могу понять, почему это не будет работать на Serverlets...
P.S Я не могу получить исходный код до выходных, поскольку внешний SSH отключен в моем офисе: (
Ответ 5
SSLHandshakeException можно решить двумя способами.
Ответ 6
Есть лучшая альтернатива доверию всем сертификатам: создайте TrustStore
которое определенно доверяет данному сертификату, и используйте его для создания SSLContext
из которого можно получить SSLSocketFactory
для установки на HttpsURLConnection
. Вот полный код:
File crtFile = new File("server.crt");
Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(new FileInputStream(crtFile));
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("server", certificate);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection();
connection.setSSLSocketFactory(sslContext.getSocketFactory());
Вы также можете загрузить KeyStore
непосредственно из файла или получить сертификат X.509 из любого надежного источника.
Обратите внимание, что с этим кодом сертификаты в cacerts
не будут использоваться. Этот конкретный HttpsURLConnection
будет доверять только этому конкретному сертификату.
Ответ 7
Пожалуйста, прочитайте эту статью, чтобы понять проблему и решить эту проблему:
https://blog.mindorks.com/handle-ssl-https-certification-path-exception-for-java-applications-1b13c751f1e7
Ответ 8
Теперь я решил эту проблему таким образом,
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.OutputStream;
// Create a trust manager that does not validate certificate chains like the
default TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
//No need to implement.
}
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
//No need to implement.
}
}
};
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
System.out.println(e);
}