Статьи

Игнорирование самоподписанных сертификатов в Java

Проблема, с которой я сталкивался несколько раз в своей карьере, заключается в том, что мы иногда хотим использовать самозаверяющие сертификаты для целей разработки или тестирования. Быстрый поиск в Google показывает проблему, с которой столкнулись бесчисленные разработчики Java на протяжении многих лет.

В зависимости от конкретной проблемы с сертификатом, вы можете получить сообщение об ошибке, подобное одному из следующих, хотя я почти уверен, что есть и другие проявления:

java.security.cert.CertificateException: Untrusted Server Certificate Chain 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 

Чтобы обойти это, часто требуется изменить файлы хранилища доверенных сертификатов JDK, что может быть болезненным, и часто вы сталкиваетесь с проблемами. Кроме того, каждый разработчик в вашей команде должен будет делать то же самое, и в каждой новой среде у вас будут повторяться одни и те же проблемы.

К счастью, есть способ справиться с проблемой общим способом, который не будет обременять ваших разработчиков. Мы собираемся сосредоточиться на ванильных соединениях типа HttpURLConnection, поскольку они являются наиболее общими и все же должны помочь вам понять направление, которое следует использовать с другими библиотеками. Если вы используете Apache HttpClient, смотрите здесь .

Предупреждение: знайте, что вы делаете!

Имейте в виду, что означает использование этого кода: это означает, что вам вообще не нужно проверять хост и вы используете SSL только для шифрования сообщений. Вы не предотвращаете атаки типа «человек посередине» и не проверяете, что вы подключены к тому хосту, которым себя считаете. Обычно это сводится к нескольким действительным случаям:

  1. вы работаете в закрытой локальной сети. Вы не подвержены перехвату ваших запросов злоумышленником (или, если это так, у вас есть большие проблемы).
  2. Вы находитесь в среде тестирования или разработки, где защита связи не важна.

Если это соответствует вашим потребностям, тогда продолжайте. В противном случае, возможно, подумайте дважды, что вы пытаетесь достичь.

Решение: изменение доверительных управляющих

Теперь, когда мы прошли этот отказ от ответственности, мы можем решить актуальную проблему под рукой. Java позволяет нам управлять объектами, ответственными за проверку хоста и сертификата для HttpsURLConnection. Это может быть сделано в глобальном масштабе, но я уверен, что те из вас, кто имеет опыт, будут испытывать страх перед мыслью о столь радикальном изменении. К счастью, мы также можем сделать это для каждого запроса, и так как примеры этого трудно найти в Интернете, я предоставил код ниже. Этот подход хорош, поскольку вам не нужно возиться с заменой реализаций SSLSocketFactory на глобальном уровне.

Не стесняйтесь захватить это и использовать это в своем проекте.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.mycompany.http;
 
import java.net.*;
import javax.net.ssl.*;
import java.security.*;
import java.security.cert.*;
 
public class TrustModifier {
   private static final TrustingHostnameVerifier
      TRUSTING_HOSTNAME_VERIFIER = new TrustingHostnameVerifier();
   private static SSLSocketFactory factory;
 
   /** Call this with any HttpURLConnection, and it will
    modify the trust settings if it is an HTTPS connection. */
   public static void relaxHostChecking(HttpURLConnection conn)
       throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
 
      if (conn instanceof HttpsURLConnection) {
         HttpsURLConnection httpsConnection = (HttpsURLConnection) conn;
         SSLSocketFactory factory = prepFactory(httpsConnection);
         httpsConnection.setSSLSocketFactory(factory);
         httpsConnection.setHostnameVerifier(TRUSTING_HOSTNAME_VERIFIER);
      }
   }
 
   static synchronized SSLSocketFactory
            prepFactory(HttpsURLConnection httpsConnection)
            throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
 
      if (factory == null) {
         SSLContext ctx = SSLContext.getInstance("TLS");
         ctx.init(null, new TrustManager[]{ new AlwaysTrustManager() }, null);
         factory = ctx.getSocketFactory();
      }
      return factory;
   }
 
   private static final class TrustingHostnameVerifier implements HostnameVerifier {
      public boolean verify(String hostname, SSLSession session) {
         return true;
      }
   }
 
   private static class AlwaysTrustManager implements X509TrustManager {
      public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { }
      public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { }
      public X509Certificate[] getAcceptedIssuers() { return null; }
   }
 
}

использование

Чтобы использовать приведенный выше код, просто вызовите метод relaxHostChecking (), прежде чем открывать поток:

1
2
3
4
5
6
7
8
9
URL someUrl = ... // may be HTTPS or HTTP
HttpURLConnection connection = (HttpURLConnection) someUrl.openConnection();
TrustModifier.relaxHostChecking(connection); // here's where the magic happens
 
// Now do your work!
// This connection will now live happily with expired or self-signed certificates
connection.setDoOutput(true);
OutputStream out = connection.getOutputStream();
...

Вот вам и полный пример локализованного подхода к поддержке самозаверяющих сертификатов. Это не влияет на остальную часть вашего приложения, которое по-прежнему будет иметь строгую семантику проверки хостинга. Этот пример можно расширить, чтобы использовать параметр конфигурации, чтобы определить, следует ли использовать упрощенную проверку хоста, и я рекомендую вам сделать это, если использование этого кода является главным способом облегчения разработки с использованием самозаверяющих сертификатов.

Ссылка: Игнорирование самоподписанных сертификатов на Java от наших партнеров по JCG в Carfey Software Blog .

Статьи по Теме :