Вебинары Разобраться в IT Реферальная программа
Программирование Аналитика Дизайн Маркетинг Управление проектами
7 профессий по цене одной
07:05:47:06
дн. ч. мин. сек.
10 Июл 2023
2 мин
113

Доверяя всем сертификатам с использованием HttpClient по HTTPS

Проблема, с которой часто сталкиваются начинающие разработчики Java, заключается в том, что при использовании HttpClient для подключения к серверу по HTTPS,

Проблема, с которой часто сталкиваются начинающие разработчики Java, заключается в том, что при использовании HttpClient для подключения к серверу по HTTPS, они получают исключение javax.net.ssl.SSLException: Not trusted server certificate. Это означает, что клиент не доверяет сертификату сервера.

Приведем пример кода, в котором возникает данная проблема:

public void connect() throws Exception {
    HttpPost post = new HttpPost(new URI("https://example.com"));
    post.setEntity(new StringEntity("body"));

    KeyStore trusted = KeyStore.getInstance("BKS");
    trusted.load(null, "".toCharArray());
    SSLSocketFactory sslf = new SSLSocketFactory(trusted);
    sslf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

    SchemeRegistry schemeRegistry = new SchemeRegistry();
    schemeRegistry.register(new Scheme("https", sslf, 443));
    SingleClientConnManager cm = new SingleClientConnManager(post.getParams(), schemeRegistry);

    HttpClient client = new DefaultHttpClient(cm, post.getParams());
    HttpResponse result = client.execute(post);
}

В этом коде мы создаем HTTP-клиент, который пытается подключиться к серверу по HTTPS и отправить ему POST-запрос. Мы используем SSLSocketFactory с пустым хранилищем ключей (KeyStore), что означает, что клиент не доверяет ни одному сертификату. Мы также указываем, что клиент должен доверять всем хостам, установив HostnameVerifier в ALLOW_ALL_HOSTNAME_VERIFIER.

Однако, когда мы пытаемся выполнить запрос, мы получаем исключение SSLException.

Решение

Проблема заключается в том, что, хотя мы и указываем, что хотим доверять всем хостам, мы не доверяем ни одному сертификату. Для решения этой проблемы мы можем создать TrustManager, который доверяет всем сертификатам.

public void connect() throws Exception {
    TrustManager[] trustAllCerts = new TrustManager[] {
        new X509TrustManager() {
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
            public void checkClientTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
            }
            public void checkServerTrusted(
                java.security.cert.X509Certificate[] certs, String authType) {
            }
        }
    };

    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

    // Now we can proceed as before
    HttpPost post = new HttpPost(new URI("https://example.com"));
    post.setEntity(new StringEntity("body"));

    HttpClient client = new DefaultHttpClient();
    HttpResponse result = client.execute(post);
}

В этом коде мы создаем TrustManager, который не проверяет сертификаты. Затем мы используем его для создания SSLContext, который мы устанавливаем в качестве стандартной SSLSocketFactory для HttpsURLConnection. Теперь мы можем использовать HttpClient без получения исключения SSLException.

Важно отметить, что этот подход имеет свои риски и должен использоваться только в тех случаях, когда вы абсолютно уверены, что подключаетесь к надежному серверу. Доверяя всем сертификатам, вы открываете возможность для так называемых «man-in-the-middle» атак, когда злоумышленник может перехватить и возможно изменить ваше зашифрованное соединение.

Проверь как ты усвоил материалы статьи
Пройди тест и узнай насколько ты лучше других читателей

Добавить комментарий