Модуль, который я добавляю к нашему большому 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 для принятия самозаверяющего сертификата? Могу ли я выполнить все цели, которые я имею в виду выше, или мне придется идти на компромисс? Есть ли опция, включающая файлы и каталоги и настройки конфигурации, а также код «маленький-на-нет»?
маленький, рабочий исправление: http://www.rgagnon.com/javadetails/java-fix-certificate-problem-in-HTTPS.html – 2011-08-16 14:06:49
@Hasenpriester: просьба не предлагать эту страницу. Он отключает проверку доверия. Вы не только согласитесь, что хотите получить самозаверяющий сертификат, но и принять любой сертификат, который вам представит злоумышленник MITM. – Bruno