Модуль, который я добавляю в наше большое Java-приложение, должен общаться с веб-сайтом, защищенным SSL. Проблема в том, что сайт использует самозаверяющий сертификат. У меня есть копия сертификата, чтобы убедиться, что я не сталкиваюсь с атакой «человек посередине», и мне нужно включить этот сертификат в наш код таким образом, чтобы соединение с сервером было успешным.
Вот основной код:
void sendRequest(String dataPacket) {
String urlStr = "https://host.example.com/";
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setMethod("POST");
conn.setRequestProperty("Content-Length", data.length());
conn.setDoOutput(true);
OutputStreamWriter o = new OutputStreamWriter(conn.getOutputStream());
o.write(data);
o.flush();
}
Без какой-либо дополнительной обработки для самоподписанного сертификата это происходит в conn.getOutputStream () со следующим исключением:
Exception in thread "main" 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
....
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
....
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
В идеале мой код должен научить Java принимать этот один самозаверяющий сертификат, для этого места в приложении и нигде больше.
Я знаю, что могу импортировать сертификат в хранилище центра сертификации JRE, и это позволит Java принять его. Это не тот подход, который я хочу использовать, если могу помочь; кажется очень инвазивным делать на всех машинах наших клиентов один модуль, который они могут не использовать; это повлияет на все другие приложения Java, использующие ту же JRE, и мне это не нравится, хотя шансы любого другого приложения Java, когда-либо получающего доступ к этому сайту, равны нулю. Это также не тривиальная операция: в UNIX мне нужно получить права доступа для изменения JRE таким образом.
Я также видел, что могу создать экземпляр TrustManager, который выполняет некоторую пользовательскую проверку. Похоже, я мог бы даже создать TrustManager, который делегирует реальный TrustManager во всех случаях, кроме этого одного сертификата. Но похоже, что TrustManager устанавливается глобально, и я предполагаю, что это повлияет на все другие соединения из нашего приложения, и это тоже не совсем подходит для меня.
Каков предпочтительный, стандартный или лучший способ настроить приложение Java для принятия самозаверяющего сертификата? Могу ли я достичь всех целей, которые я имею в виду выше, или мне придется идти на компромисс? Есть ли опция, включающая файлы и каталоги, а также параметры конфигурации и практически неиспользуемый код?