Довіряти всім сертифікатам за допомогою HttpClient через HTTPS


393

Нещодавно опублікував питання щодо HttpClientпонад Https ( знайдено тут ). Я просунувся, але я зіткнувся з новими проблемами. Як і в останній моїй проблемі, я не можу знайти приклад, де працює для мене. В основному я хочу, щоб мій клієнт прийняв будь-який сертифікат (тому що я коли-небудь вказував на один сервер), але я продовжую отримуватиjavax.net.ssl.SSLException: Not trusted server certificate exception.

Отже, ось що:


    public void connect() throws A_WHOLE_BUNCH_OF_EXCEPTIONS {

        HttpPost post = new HttpPost(new URI(PROD_URL));
        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);
    }

І ось я отримую помилку:

    W/System.err(  901): javax.net.ssl.SSLException: Not trusted server certificate 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:360) 
    W/System.err(  901):    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:92) 
    W/System.err(  901):    at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:321) 
    W/System.err(  901):    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:129) 
    W/System.err(  901):    at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164) 
    W/System.err(  901):    at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119) 
    W/System.err(  901):    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:348) 
    W/System.err(  901):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555) 
    W/System.err(  901):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487) 
    W/System.err(  901):    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465) 
    W/System.err(  901):    at me.harrisonlee.test.ssl.MainActivity.connect(MainActivity.java:129) 
    W/System.err(  901):    at me.harrisonlee.test.ssl.MainActivity.access$0(MainActivity.java:77) 
    W/System.err(  901):    at me.harrisonlee.test.ssl.MainActivity$2.run(MainActivity.java:49) 
    W/System.err(  901): Caused by: java.security.cert.CertificateException: java.security.InvalidAlgorithmParameterException: the trust anchors set is empty 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:157) 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:355) 
    W/System.err(  901):    ... 12 more 
    W/System.err(  901): Caused by: java.security.InvalidAlgorithmParameterException: the trust anchors set is empty 
    W/System.err(  901):    at java.security.cert.PKIXParameters.checkTrustAnchors(PKIXParameters.java:645) 
    W/System.err(  901):    at java.security.cert.PKIXParameters.<init>(PKIXParameters.java:89) 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.<init>(TrustManagerImpl.java:89) 
    W/System.err(  901):    at org.apache.harmony.xnet.provider.jsse.TrustManagerFactoryImpl.engineGetTrustManagers(TrustManagerFactoryImpl.java:134) 
    W/System.err(  901):    at javax.net.ssl.TrustManagerFactory.getTrustManagers(TrustManagerFactory.java:226)W/System.err(  901):     at org.apache.http.conn.ssl.SSLSocketFactory.createTrustManagers(SSLSocketFactory.java:263) 
    W/System.err(  901):    at org.apache.http.conn.ssl.SSLSocketFactory.<init>(SSLSocketFactory.java:190) 
    W/System.err(  901):    at org.apache.http.conn.ssl.SSLSocketFactory.<init>(SSLSocketFactory.java:216) 
    W/System.err(  901):    at me.harrisonlee.test.ssl.MainActivity.connect(MainActivity.java:107) 
    W/System.err(  901):    ... 2 more

17
Мені потрібно було це зробити для внутрішнього використання. Я дуже сподіваюся, що ви не дозволяєте користувачам за межами вашої компанії користуватися вашим додатком, оскільки ви відкрили його людині в середній атаці, і вони могли б тоді бути вразливими до того, хто викраде їх сеанс. тим не менш, мені потрібно зробити це тимчасовим для деяких тестувань, поки я не отримаю справжній сертифікат в руки ..... сподіваємось, ви робите це з тієї ж тимчасової причини або додаток використовується лише внутрішньо.
Дін Хіллер

Я випробував ці рішення на 4,3 апаш-http-клієнта, але вони здебільшого застаріли. Тут не засуджується рішення: stackoverflow.com/a/18941950/2039471
Олександр Чжен

У Java 1.6 немає підтримки SNI, що також проблематично в цих сценаріях - якщо ви не правильно побудуєте запит, ви можете отримати сертифікат, який не відповідає запиту. Див. Issues.apache.org/jira/browse/HTTPCLIENT-1119
Брон Девіс

2
Це питання наводиться в документі «Найнебезпечніший кодекс у світі» як приклад помилкових міркувань. (Науково-дослідна робота: cs.utexas.edu/~shmat/shmat_ccs12.pdf )
mk_

Відповіді:


421

Примітка. Не застосовуйте це у виробничому коді, який ви коли-небудь будете використовувати в мережі, якій ви не повністю довіряєте. Особливо все, що відбувається через загальнодоступний Інтернет.

Ваше запитання - це саме те, що я хочу знати. Після того, як я здійснив кілька пошуків, висновок такий.

У HttpClient способом слід створити користувальницький клас із org.apache.http.conn.ssl.SSLSocketFactory, а не того самого org.apache.http.conn.ssl.SSLSocketFactory. Деякі підказки можна знайти у цій публікації. Спеціальна обробка SSL перестала працювати на Android 2.2 FroYo .

Приклад:

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.conn.ssl.SSLSocketFactory;
public class MySSLSocketFactory extends SSLSocketFactory {
    SSLContext sslContext = SSLContext.getInstance("TLS");

    public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
        super(truststore);

        TrustManager tm = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };

        sslContext.init(null, new TrustManager[] { tm }, null);
    }

    @Override
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
        return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    }

    @Override
    public Socket createSocket() throws IOException {
        return sslContext.getSocketFactory().createSocket();
    }
}

і використовувати цей клас під час створення екземпляра HttpClient.

public HttpClient getNewHttpClient() {
    try {
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        trustStore.load(null, null);

        MySSLSocketFactory sf = new MySSLSocketFactory(trustStore);
        sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

        HttpParams params = new BasicHttpParams();
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        registry.register(new Scheme("https", sf, 443));

        ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

        return new DefaultHttpClient(ccm, params);
    } catch (Exception e) {
        return new DefaultHttpClient();
    }
}

BTW, посилання нижче призначене для того, хто шукає рішення HttpURLConnection. HTTP-з'єднання Android

Я випробував вищевказані два типи рішень на froyo, і всі вони працюють як шарм у моїх випадках. Нарешті, використання HttpURLConnection може зіткнутися з проблемами переадресації, але це поза темою.

Примітка: Перш ніж ви вирішите довіряти всім сертифікатам, ви, ймовірно, повинні добре знати сайт та не буде шкодити його кінцевому користувачеві.

Дійсно, ризик, який ви берете на себе, слід уважно розглядати, включаючи ефект знущання над хакерським сайтом, згаданий у наступних коментарях, який я глибоко оцінив. У деяких випадках, хоча це може бути важко піклуватися про всі сертифікати, вам краще знати неявні недоліки, щоб довіряти всім їм.


150
у цій відповіді, мабуть, слід зазначити, що довіра до всіх сертифікатів жахливо небезпечна і зводить нанівець цілі ssl ...
yanokwa

22
@sweeney - За винятком того, що ви не гарантуєте, що ви спілкуєтесь із сервером, на якому ви думаєте. Якщо хтось вимкнув DNS-сервер, ви можете передавати ключ шифрування з сервером хакера.
Річард Шалай

12
@sweeney Іншими словами, ви зараз піддаєтеся атакам "людина-в-середині". Також слід зазначити, що цей код не відповідає специфікації: перевірте Javadoc. getAcceptedIssuers()не дозволяється повернути null.
Маркіз Лорн

25
-1 Тому що це жахлива ідея приймати всі сертифікати. Дуже погано, що існує стільки блогів та навчальних посібників, які із задоволенням направляють розробників Java по шляху вчинення не так.
Тім Бендер

57
+1 Тому що мені було потрібно швидке рішення лише для налагодження. Я б не використовував це у виробництві через занепокоєння щодо безпеки, про які згадували інші, але саме це мені було потрібно для тестування. Дякую!
Данація

495

В основному у вас є чотири потенційні рішення, щоб виправити виключення "Не довірено" на Android за допомогою httpclient:

  1. Довіряйте всім сертифікатам. Не робіть цього, якщо ви дійсно не знаєте, що робите.
  2. Створіть спеціальний SSLSocketFactory, який довіряє лише вашому сертифікату. Це працює, якщо ви точно знаєте, до яких серверів ви збираєтесь підключитися, але як тільки вам доведеться підключитися до нового сервера з іншим сертифікатом SSL, вам потрібно буде оновити додаток.
  3. Створіть файл магазину брелоків, який містить "головний список" сертифікатів Android, а потім додайте свій власний. Якщо будь-який із цих сертифікатів закінчується в дорозі, ви несете відповідальність за оновлення їх у своєму додатку. Я не можу придумати причину для цього.
  4. Створіть спеціальний SSLSocketFactory, який використовує вбудований сертифікат KeyStore, але повертається на альтернативний KeyStore для того, що не вдасться перевірити за замовчуванням.

У цій відповіді використовується рішення №4, яке, як мені здається, є найбільш надійним.

Рішення полягає у використанні SSLSocketFactory, який може приймати декілька KeyStores, що дозволяє постачати свій KeyStore власними сертифікатами. Це дозволяє завантажувати додаткові сертифікати вищого рівня, наприклад, Thawte, які можуть бути відсутні на деяких пристроях Android. Це також дозволяє завантажувати власні самопідписані сертифікати. Спершу він використовуватиме вбудовані сертифікати пристрою за замовчуванням, а потім додаватиме додаткові сертифікати лише за необхідності.

По-перше, ви хочете визначити, який церт вам не вистачає в KeyStore. Виконайте таку команду:

openssl s_client -connect www.yourserver.com:443

І ви побачите вихідний такий:

Certificate chain
 0 s:/O=www.yourserver.com/OU=Go to 
   https://www.thawte.com/repository/index.html/OU=Thawte SSL123 
   certificate/OU=Domain Validated/CN=www.yourserver.com
   i:/C=US/O=Thawte, Inc./OU=Domain Validated SSL/CN=Thawte DV SSL CA
 1 s:/C=US/O=Thawte, Inc./OU=Domain Validated SSL/CN=Thawte DV SSL CA
   i:/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 
   2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA

Як бачите, наш кореневий сертифікат походить від Thawte. Перейдіть на веб-сайт свого постачальника і знайдіть відповідний сертифікат. Для нас це було тут , і ви можете бачити, що нам потрібне було те, яке було визначено Copyright 2006.

Якщо ви використовуєте самопідписаний сертифікат, вам не потрібно було робити попередній крок, оскільки у вас вже є ваш сертифікат.

Потім створіть файл зберігання ключів, що містить відсутній сертифікат підпису. Crazybob містить деталі, як це зробити на Android , але ідея полягає в тому, щоб зробити наступне:

Якщо у вас його ще немає, завантажте бібліотеку постачальників замовлених замків з веб-сайту : http://www.bouncycastle.org/latest_releases.html . Це буде продовжено на вашому занятті нижче.

Виконайте команду для вилучення сертифіката з сервера та створення файлу pem. У цьому випадку mycert.pem.

echo | openssl s_client -connect ${MY_SERVER}:443 2>&1 | \
 sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > mycert.pem

Потім запустіть наступні команди, щоб створити сховище ключів.

export CLASSPATH=/path/to/bouncycastle/bcprov-jdk15on-155.jar
CERTSTORE=res/raw/mystore.bks
if [ -a $CERTSTORE ]; then
    rm $CERTSTORE || exit 1
fi
keytool \
      -import \
      -v \
      -trustcacerts \
      -alias 0 \
      -file <(openssl x509 -in mycert.pem) \
      -keystore $CERTSTORE \
      -storetype BKS \
      -provider org.bouncycastle.jce.provider.BouncyCastleProvider \
      -providerpath /path/to/bouncycastle/bcprov-jdk15on-155.jar \
      -storepass some-password

Ви помітите, що вищезазначений сценарій розміщує результат res/raw/mystore.bks. Тепер у вас є файл, який ви завантажите у додаток для Android, який надає відсутні сертифікати.

Для цього зареєструйте свій SSLSocketFactory для схеми SSL:

final SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", createAdditionalCertsSSLSocketFactory(), 443));

// and then however you create your connection manager, I use ThreadSafeClientConnManager
final HttpParams params = new BasicHttpParams();
...
final ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params,schemeRegistry);

Щоб створити свій SSLSocketFactory:

protected org.apache.http.conn.ssl.SSLSocketFactory createAdditionalCertsSSLSocketFactory() {
    try {
        final KeyStore ks = KeyStore.getInstance("BKS");

        // the bks file we generated above
        final InputStream in = context.getResources().openRawResource( R.raw.mystore);  
        try {
            // don't forget to put the password used above in strings.xml/mystore_password
            ks.load(in, context.getString( R.string.mystore_password ).toCharArray());
        } finally {
            in.close();
        }

        return new AdditionalKeyStoresSSLSocketFactory(ks);

    } catch( Exception e ) {
        throw new RuntimeException(e);
    }
}

І нарешті, код AdditionalKeyStoresSSLSocketFactory, який приймає ваш новий KeyStore і перевіряє, чи не вбудований KeyStore не підтвердив сертифікат SSL:

/**
 * Allows you to trust certificates from additional KeyStores in addition to
 * the default KeyStore
 */
public class AdditionalKeyStoresSSLSocketFactory extends SSLSocketFactory {
    protected SSLContext sslContext = SSLContext.getInstance("TLS");

    public AdditionalKeyStoresSSLSocketFactory(KeyStore keyStore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
        super(null, null, null, null, null, null);
        sslContext.init(null, new TrustManager[]{new AdditionalKeyStoresTrustManager(keyStore)}, null);
    }

    @Override
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
        return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    }

    @Override
    public Socket createSocket() throws IOException {
        return sslContext.getSocketFactory().createSocket();
    }



    /**
     * Based on http://download.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#X509TrustManager
     */
    public static class AdditionalKeyStoresTrustManager implements X509TrustManager {

        protected ArrayList<X509TrustManager> x509TrustManagers = new ArrayList<X509TrustManager>();


        protected AdditionalKeyStoresTrustManager(KeyStore... additionalkeyStores) {
            final ArrayList<TrustManagerFactory> factories = new ArrayList<TrustManagerFactory>();

            try {
                // The default Trustmanager with default keystore
                final TrustManagerFactory original = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                original.init((KeyStore) null);
                factories.add(original);

                for( KeyStore keyStore : additionalkeyStores ) {
                    final TrustManagerFactory additionalCerts = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                    additionalCerts.init(keyStore);
                    factories.add(additionalCerts);
                }

            } catch (Exception e) {
                throw new RuntimeException(e);
            }



            /*
             * Iterate over the returned trustmanagers, and hold on
             * to any that are X509TrustManagers
             */
            for (TrustManagerFactory tmf : factories)
                for( TrustManager tm : tmf.getTrustManagers() )
                    if (tm instanceof X509TrustManager)
                        x509TrustManagers.add( (X509TrustManager)tm );


            if( x509TrustManagers.size()==0 )
                throw new RuntimeException("Couldn't find any X509TrustManagers");

        }

        /*
         * Delegate to the default trust manager.
         */
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            final X509TrustManager defaultX509TrustManager = x509TrustManagers.get(0);
            defaultX509TrustManager.checkClientTrusted(chain, authType);
        }

        /*
         * Loop over the trustmanagers until we find one that accepts our server
         */
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            for( X509TrustManager tm : x509TrustManagers ) {
                try {
                    tm.checkServerTrusted(chain,authType);
                    return;
                } catch( CertificateException e ) {
                    // ignore
                }
            }
            throw new CertificateException();
        }

        public X509Certificate[] getAcceptedIssuers() {
            final ArrayList<X509Certificate> list = new ArrayList<X509Certificate>();
            for( X509TrustManager tm : x509TrustManagers )
                list.addAll(Arrays.asList(tm.getAcceptedIssuers()));
            return list.toArray(new X509Certificate[list.size()]);
        }
    }

}

Привіт @emmby, здається, це ідеальна відповідь на мою проблему, але я все одно не отримую зв'язку SSL. Чи можете ви, будь ласка, поглянути на це? http://stackoverflow.com/questions/7822381/need-help-understanding-certificate-chains
Маттіас Б

Дякуємо за чудову запис @emmby! Я іноді отримую дуже велику затримку, а потім javax.net.ssl.SSLException: Помилка читання:. Будь-яка ідея? Як я можу встановити тайм-аут, якщо рішення таке ж, як stackoverflow.com/questions/5909308/android-2-3-4-ssl-problem ?
Едвін Еванс

3
@emmby, не могли б ви сказати, куди слід поставити цей код експорту CLASSPATH = bcprov-jdk16-145.jar CERTSTORE = res / raw / mystore.bks, якщо [-a $ CERTSTORE]; тоді rm $ CERTSTORE || вихід 1 fi keytool \ -import \ -v \ -trustcacerts \ -alias 0 \ -file <(openssl x509 -in mycert.pem) \ -keystore $ CERTSTORE \ -storetype BKS \ -provider org.bouncycastle.jce.provider. BouncyCastleProvider \ -providerpath /usr/share/java/bcprov.jar \ -затримати деякий пароль
Rikki Tikki Tavi

1
Гей @emmby Я використовую ваше рішення у своєму додатку та використовую самопідписаний сервер мого сервера, але отримую CertificateException () у checkServerTrusted () метод. Я спробував прокоментувати виняток, що кидає, і він працює. якщо він не підтверджує мій сервер cert, то чи можу я обробляти його іншим способом? Чи можете ви, будь ласка, керувати, яке найкраще рішення в цьому випадку?
Анкіт

7
Це слід позначити як правильну відповідь. Один з найбільш ретельних і добре написаних відповідей, які я коли-небудь бачив на SO. Допінг
Качі

74

Додайте цей код до, HttpsURLConnectionі це буде зроблено. Зрозумів.

private void trustEveryone() { 
    try { 
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier(){ 
                    public boolean verify(String hostname, SSLSession session) { 
                            return true; 
                    }}); 
            SSLContext context = SSLContext.getInstance("TLS"); 
            context.init(null, new X509TrustManager[]{new X509TrustManager(){ 
                    public void checkClientTrusted(X509Certificate[] chain, 
                                    String authType) throws CertificateException {} 
                    public void checkServerTrusted(X509Certificate[] chain, 
                                    String authType) throws CertificateException {} 
                    public X509Certificate[] getAcceptedIssuers() { 
                            return new X509Certificate[0]; 
                    }}}, new SecureRandom()); 
            HttpsURLConnection.setDefaultSSLSocketFactory( 
                            context.getSocketFactory()); 
    } catch (Exception e) { // should never happen 
            e.printStackTrace(); 
    } 
} 

Я сподіваюся, що це вам допоможе.


22
Дивіться зауваження вище під прийнятою відповіддю. Це "рішення" є докорінно небезпечним.
Маркіз Лорн

5
Це ідеальне вирішення питань та питань. Короткий і «просто працює».
Стів Сміт

5
Ідеальна відповідь для тестування !!! І так, це погано використовувати у виробництві, але давай ... це повинно бути зрозуміло всім, хто дивиться на назву питання. Він як і раніше відповідає найкраще / найкоротше / з тим самим (не) рівнем безпеки!
Левіт

34

Це погана ідея. Довіряти будь-якому сертифікату лише (дуже) трохи краще, ніж використовувати SSL взагалі. Коли ви говорите "Я хочу, щоб мій клієнт прийняв будь-який сертифікат (тому що я коли-небудь вказував на один сервер)", ти припускаєш, що це означає, що якимось чином вказівка ​​на "один сервер" є безпечною, а це не в загальнодоступній мережі.

Ви повністю відкриті для атаки "посередника", довіряючи будь-якому сертифікату. Будь-хто може проксі підключити ваше з'єднання, встановивши окреме SSL-з'єднання з вами та з кінцевим сервером. Потім MITM має доступ до всього запиту та відповіді. Якщо вам справді не потрібен SSL в першу чергу (у вашому повідомленні немає нічого чутливого і не робиться автентифікація), вам не слід довіряти всім сертифікатам наосліп.

Вам слід розглянути можливість додавання відкритого cert до jks за допомогою keytool і використовувати його для створення вашої фабрики сокетів, наприклад цього:

    KeyStore ks = KeyStore.getInstance("JKS");

    // get user password and file input stream
    char[] password = ("mykspassword")).toCharArray();
    ClassLoader cl = this.getClass().getClassLoader();
    InputStream stream = cl.getResourceAsStream("myjks.jks");
    ks.load(stream, password);
    stream.close();

    SSLContext sc = SSLContext.getInstance("TLS");
    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
    TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");

    kmf.init(ks, password);
    tmf.init(ks);

    sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(),null);

    return sc.getSocketFactory();

У цьому є один застереження, на яке слід стежити. Сертифікат закінчується в кінцевому підсумку, і в цей час код перестане працювати. Ви можете легко визначити, коли це станеться, поглянувши на церт.


5
Якщо ви не використовуєте автентифікацію клієнтських сертифікатів, з боку клієнта вам не потрібен керуючий ключами (використовуйте nullв SSLContext.init). You should also use the default algorithms (KMF/TMF.getDefaultAlgorithm() ), instead of hard-coding SunX509` (тим більше, що за замовчуванням для TMF насправді знаходиться PKIXJVM Sun / Oracle).
Бруно

Існує готовий до використання файл кореневих сертифікатів? (як це роблять браузери)
dani herrera

Звідки myjks.jksвзявся?
zionpi

1
@zionpi Створено за допомогою Java "keytool".
Dan

22

Ви можете відключити перевірку SSL HttpURLConnection для тестування таким чином, оскільки API 8:

    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    if (conn instanceof HttpsURLConnection) {
        HttpsURLConnection httpsConn = (HttpsURLConnection) conn;
        httpsConn.setSSLSocketFactory(SSLCertificateSocketFactory.getInsecure(0, null));
        httpsConn.setHostnameVerifier(new AllowAllHostnameVerifier());
    }

2
org.apache.http.conn.ssl.AllowAllHostnameVerifierзастаріло.
zackygaurav

2
@zackygaurav За словами javadoc , AllowAllHostnameVerifierйого замінюють на NoopHostnameVerifier"
DLight

10

API HttpComponents змінився. Він працює з наведеним нижче кодом.

public static HttpClient getTestHttpClient() {
    try {
        SSLSocketFactory sf = new SSLSocketFactory(new TrustStrategy(){
            @Override
            public boolean isTrusted(X509Certificate[] chain,
                    String authType) throws CertificateException {
                return true;
            }
        }, new AllowAllHostnameVerifier());

        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("https",8444, sf));
        ClientConnectionManager ccm = new ThreadSafeClientConnManager(registry);
        return new DefaultHttpClient(ccm);
    } catch (Exception e) {
        e.printStackTrace();
        return new DefaultHttpClient();
    }
}

Використання спеціальної стратегії довіри - правильна відповідь. Дякую.
Метт Фрідман

10

Код, наведений вище в https://stackoverflow.com/a/6378872/1553004, є правильним, окрім цього ОБОВ'ЯЗКОВО також викликати перевірку імені хоста:

    @Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
    SSLSocket sslSocket = (SSLSocket)sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    getHostnameVerifier().verify(host, sslSocket);
    return sslSocket;
}

Я підписався на stackoverflow виразно, щоб додати це виправлення. Прислухайтесь до мого попередження!


Після того, як ви підтвердите сертифікат таким чином під час першого з'єднання, що ви робите з наступними з'єднаннями? Чи використовуєте ви знання, отримані з першого зв’язку? Що робити, якщо під час підключення 3 використовується підроблений сертифікат з тим самим іменем?
jww

6

Я додаю відповідь для тих, хто використовує httpclient-4.5, і, ймовірно, працює і для 4.4.

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.fluent.ContentResponseHandler;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;



public class HttpClientUtils{

public static HttpClient getHttpClientWithoutSslValidation_UsingHttpClient_4_5_2() {
    try {
        SSLContextBuilder builder = new SSLContextBuilder();
        builder.loadTrustMaterial(null, new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                return true;
            }
        });
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(), new NoopHostnameVerifier());
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); 
        return httpclient;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
}

що таке новий клас NoopHostnameVerifier ()?
Муштакім Ахмед Ансарі

1
@MushtakimAhmedAnsari From docs: "NO_OP HostnameVerifier по суті вимикає перевірку імені хоста. Ця реалізація не працює, і ніколи не викидає SSLException."
рейдеркостін

Дякую за чудову відповідь. Це повинно отримати більше голосів.
Abhay Dwivedi

Як я ним користуюся? або ви припускаєте, що просто наявність класу буде замінено перевірку сертифікатів ssl?
бехеліт

так. що httpClient при використанні не підтверджує сертифікати https
рейдеркостін

4

Довіра всіх сертифікатів не була для мене реальною альтернативою, тому я зробив наступне, щоб отримати HttpsURLConnection, щоб довірити новий сертифікат (див. Також http://nelenkov.blogspot.jp/2011/12/using-custom-certificate-trust-store- on.html ).

  1. Отримайте сертифікат; Я це зробив, експортувавши сертифікат у Firefox (натисніть на маленький значок блокування, отримайте деталі сертифікату, натисніть "експортувати"), а потім використовуйте portecle для експорту довіри (BKS).

  2. Завантажте Truststore з /res/raw/geotrust_cert.bks із таким кодом:

        final KeyStore trustStore = KeyStore.getInstance("BKS");
        final InputStream in = context.getResources().openRawResource(
                R.raw.geotrust_cert);
        trustStore.load(in, null);
    
        final TrustManagerFactory tmf = TrustManagerFactory
                .getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(trustStore);
    
        final SSLContext sslCtx = SSLContext.getInstance("TLS");
        sslCtx.init(null, tmf.getTrustManagers(),
                new java.security.SecureRandom());
    
        HttpsURLConnection.setDefaultSSLSocketFactory(sslCtx
                .getSocketFactory());

Я отримую цю помилку. IOExceptionjavax.net.ssl.SSLPeerUnverifiedException: No peer certificate. Це робиться при дійсному виконанні виклику на HttpClient після того, як описана вище настройка.
Майкл

3

Ось набагато проста версія, що використовує 4.1.2 httpclient-код. Потім це можна змінити на будь-який алгоритм довіри, який Ви вважаєте за потрібне.

public static HttpClient getTestHttpClient() {
    try {
        SSLSocketFactory sf = new SSLSocketFactory(new TrustStrategy(){
            @Override
            public boolean isTrusted(X509Certificate[] chain,
                    String authType) throws CertificateException {
                return true;
            }
        });
        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("https", 443, sf));
        ClientConnectionManager ccm = new ThreadSafeClientConnManager(registry);
        return new DefaultHttpClient(ccm);
    } catch (Exception e) {
        return new DefaultHttpClient();
    }
}

3

Я переглянув відповідь "emmby" (відповів 16 червня '11 о 21:29), пункт №4: "Створіть власну SSLSocketFactory, який використовує вбудований сертифікат KeyStore, але повертається на альтернативний KeyStore для всього, що не вдасться для підтвердження за замовчуванням. "

Це спрощена реалізація. Завантажте системну сховище ключів та об'єднайте її із сховищем клавіш програми.

public HttpClient getNewHttpClient() {
    try {
        InputStream in = null;
        // Load default system keystore
        KeyStore trusted = KeyStore.getInstance(KeyStore.getDefaultType()); 
        try {
            in = new BufferedInputStream(new FileInputStream(System.getProperty("javax.net.ssl.trustStore"))); // Normally: "/system/etc/security/cacerts.bks"
            trusted.load(in, null); // no password is "changeit"
        } finally {
            if (in != null) {
                in.close();
                in = null;
            }
        }

        // Load application keystore & merge with system
        try {
            KeyStore appTrusted = KeyStore.getInstance("BKS"); 
            in = context.getResources().openRawResource(R.raw.mykeystore);
            appTrusted.load(in, null); // no password is "changeit"
            for (Enumeration<String> e = appTrusted.aliases(); e.hasMoreElements();) {
                final String alias = e.nextElement();
                final KeyStore.Entry entry = appTrusted.getEntry(alias, null);
                trusted.setEntry(System.currentTimeMillis() + ":" + alias, entry, null);
            }
        } finally {
            if (in != null) {
                in.close();
                in = null;
            }
        }

        HttpParams params = new BasicHttpParams();
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

        SSLSocketFactory sf = new SSLSocketFactory(trusted);
        sf.setHostnameVerifier(SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);

        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        registry.register(new Scheme("https", sf, 443));

        ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

        return new DefaultHttpClient(ccm, params);
    } catch (Exception e) {
        return new DefaultHttpClient();
    }
}

Простий режим для перетворення з JKS в BKS:

keytool -importkeystore -destkeystore cacerts.bks -deststoretype BKS -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath bcprov-jdk16-141.jar -deststorepass changeit -srcstorepass changeit -srckeystore $JAVA_HOME/jre/lib/security/cacerts -srcstoretype JKS -noprompt

* Примітка: в Android 4.0 (ICS) Trust Store змінився, додаткова інформація: http://nelenkov.blogspot.com.es/2011/12/ics-trust-store-implementation.html


3

Для тих, хто хотів би дозволити всі сертифікати працювати (для тестування) над OAuth, виконайте наступні дії:

1) Завантажте вихідний код API Android OAuth тут: https://github.com/kaeppler/signpost

2) Знайдіть файл класу "CommonsHttpOAuthProvider"

3) Змініть його, як показано нижче:

public class CommonsHttpOAuthProvider extends AbstractOAuthProvider {

private static final long serialVersionUID = 1L;

private transient HttpClient httpClient;

public CommonsHttpOAuthProvider(String requestTokenEndpointUrl, String accessTokenEndpointUrl,
        String authorizationWebsiteUrl) {
    super(requestTokenEndpointUrl, accessTokenEndpointUrl, authorizationWebsiteUrl);


    //this.httpClient = new DefaultHttpClient();//Version implemented and that throws the famous "javax.net.ssl.SSLException: Not trusted server certificate" if the certificate is not signed with a CA
    this.httpClient = MySSLSocketFactory.getNewHttpClient();//This will work with all certificates (for testing purposes only)
}

Вище "MySSLSocketFactory" заснований на прийнятій відповіді. Щоб зробити це ще простіше, тут йде повний клас:

package com.netcomps.oauth_example;

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;

//http://stackoverflow.com/questions/2642777/trusting-all-certificates-using-httpclient-over-https
public class MySSLSocketFactory extends SSLSocketFactory {

    SSLContext sslContext = SSLContext.getInstance("TLS");

public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {

    super(truststore);
    TrustManager tm = new X509TrustManager() {

        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    };

    sslContext.init(null, new TrustManager[] { tm }, null);
}

@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
    return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
}

@Override
public Socket createSocket() throws IOException {
    return sslContext.getSocketFactory().createSocket();
}



public static HttpClient getNewHttpClient() {

    try {
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        trustStore.load(null, null);

        SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
        sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

        HttpParams params = new BasicHttpParams();
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        registry.register(new Scheme("https", sf, 443));

        ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

        return new DefaultHttpClient(ccm, params);

    } catch (Exception e) {
        return new DefaultHttpClient();
    }
}

}

Сподіваюся, що це комусь допоможе.


1
Питання було HttpClientі HTTPS; не OAuth для Android від проекту GitHub.
jww

3

Я використав це, і він працює для мене на всіх ОС.

/**
 * Disables the SSL certificate checking for new instances of {@link HttpsURLConnection} This has been created to
 * aid testing on a local box, not for use on production.
 */


private static void disableSSLCertificateChecking() {
    TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        @Override
        public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
            // Not implemented
        }

        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
            // Not implemented
        }
    } };

    try {
        SSLContext sc = SSLContext.getInstance("TLS");

        sc.init(null, trustAllCerts, new java.security.SecureRandom());

        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    } catch (KeyManagementException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
}

Привіт @ yegor256, я використовую цей код, але все ще виникає проблема рукостискання з SSL
user2028

1

Просто додавання -Dtrust_all_cert=trueдо аргументів VM повинно зробити. Цей аргумент наказує Java ігнорувати перевірки сертифікатів.


4
Не додайте однакову відповідь на кілька запитань. Дайте відповідь найкращому, а решту позначте як дублікати. Див. Чи прийнятно додати дублюючу відповідь на кілька запитань?
Петтер Фріберг

0

Будь-яка організація, яка все ще бореться зі сертифікатами StartCom SSL на Android 2.1, відвідайте https://www.startssl.com/certs/ та завантажте ca.pem, тепер у відповіді, наданій @emmby замінити

`export CLASSPATH=bcprov-jdk16-145.jar
 CERTSTORE=res/raw/mystore.bks
      if [ -a $CERTSTORE ]; then
          rm $CERTSTORE || exit 1
      fi
 keytool \
  -import \
  -v \
  -trustcacerts \
  -alias 0 \
  -file <(openssl x509 -in mycert.pem) \
  -keystore $CERTSTORE \
  -storetype BKS \
  -provider org.bouncycastle.jce.provider.BouncyCastleProvider \
  -providerpath /usr/share/java/bcprov.jar \
  -storepass some-password`

з

 `export CLASSPATH=bcprov-jdk16-145.jar
 CERTSTORE=res/raw/mystore.bks
      if [ -a $CERTSTORE ]; then
          rm $CERTSTORE || exit 1
      fi
 keytool \
  -import \
  -v \
  -trustcacerts \
  -alias 0 \
  -file <(openssl x509 -in ca.pem) \
  -keystore $CERTSTORE \
  -storetype BKS \
  -provider org.bouncycastle.jce.provider.BouncyCastleProvider \
  -providerpath /usr/share/java/bcprov.jar \
  -storepass some-password`

Має працювати поза коробкою. Я боровся з цим понад день навіть після ідеальної відповіді @emmby . Сподіваюся, це комусь допоможе ...


0

використовувати цей клас

public class WCFs
{
    //  https://192.168.30.8/myservice.svc?wsdl
private static final String NAMESPACE = "http://tempuri.org/";
private static final String URL = "192.168.30.8";
private static final String SERVICE = "/myservice.svc?wsdl";
private static String SOAP_ACTION = "http://tempuri.org/iWCFserviceMe/";


public static Thread myMethod(Runnable rp)
{
    String METHOD_NAME = "myMethod";

    SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);

    request.addProperty("Message", "Https WCF Running...");
    return _call(rp,METHOD_NAME, request);
}

protected static HandlerThread _call(final RunProcess rp,final String METHOD_NAME, SoapObject soapReq)
{
    final SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
    int TimeOut = 5*1000;

    envelope.dotNet = true;
    envelope.bodyOut = soapReq;
    envelope.setOutputSoapObject(soapReq);

    final HttpsTransportSE httpTransport_net = new HttpsTransportSE(URL, 443, SERVICE, TimeOut);

    try
    {
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() // use this section if crt file is handmake
        {
            @Override
            public boolean verify(String hostname, SSLSession session)
            {
                return true;
            }
        });

        KeyStore k = getFromRaw(R.raw.key, "PKCS12", "password");
        ((HttpsServiceConnectionSE) httpTransport_net.getServiceConnection()).setSSLSocketFactory(getSSLSocketFactory(k, "SSL"));


    }
    catch(Exception e){}

    HandlerThread thread = new HandlerThread("wcfTd"+ Generator.getRandomNumber())
    {
        @Override
        public void run()
        {
            Handler h = new Handler(Looper.getMainLooper());
            Object response = null;

            for(int i=0; i<4; i++)
            {
                response = send(envelope, httpTransport_net , METHOD_NAME, null);

                try
                {if(Thread.currentThread().isInterrupted()) return;}catch(Exception e){}

                if(response != null)
                    break;

                ThreadHelper.threadSleep(250);
            }

            if(response != null)
            {
                if(rp != null)
                {
                    rp.setArguments(response.toString());
                    h.post(rp);
                }
            }
            else
            {
                if(Thread.currentThread().isInterrupted())
                    return;

                if(rp != null)
                {
                    rp.setExceptionState(true);
                    h.post(rp);
                }
            }

            ThreadHelper.stopThread(this);
        }
    };

    thread.start();

    return thread;
}


private static Object send(SoapSerializationEnvelope envelope, HttpTransportSE androidHttpTransport, String METHOD_NAME, List<HeaderProperty> headerList)
{
    try
    {
        if(headerList != null)
            androidHttpTransport.call(SOAP_ACTION + METHOD_NAME, envelope, headerList);
        else
            androidHttpTransport.call(SOAP_ACTION + METHOD_NAME, envelope);

        Object res = envelope.getResponse();

        if(res instanceof SoapPrimitive)
            return (SoapPrimitive) envelope.getResponse();
        else if(res instanceof SoapObject)
            return ((SoapObject) envelope.getResponse());
    }
    catch(Exception e)
    {}

    return null;
}

public static KeyStore getFromRaw(@RawRes int id, String algorithm, String filePassword)
{
    try
    {
        InputStream inputStream = ResourceMaster.openRaw(id);
        KeyStore keystore = KeyStore.getInstance(algorithm);
        keystore.load(inputStream, filePassword.toCharArray());
        inputStream.close();

        return keystore;
    }
    catch(Exception e)
    {}

    return null;
}

public static SSLSocketFactory getSSLSocketFactory(KeyStore trustKey, String SSLAlgorithm)
{
    try
    {
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(trustKey);

        SSLContext context = SSLContext.getInstance(SSLAlgorithm);//"SSL" "TLS"
        context.init(null, tmf.getTrustManagers(), null);

        return context.getSocketFactory();
    }
    catch(Exception e){}

    return null;
}

}


0

введіть тут опис зображення

Не вдалося sspi в xamarin android.

Я знайшов це рішення; поставте цей код перед тим, як потрапити на HTTPS-посилання

const SslProtocols _Tls12 = (SslProtocols)0x00000C00;
const SecurityProtocolType Tls12 = (SecurityProtocolType)_Tls12;
ServicePointManager.SecurityProtocol = Tls12;

-3

працювати з усіма https

httpClient = new DefaultHttpClient();

SSLContext ctx = SSLContext.getInstance("TLS");
X509TrustManager tm = new X509TrustManager() {
    public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { }

    public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { }

    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }
};

ctx.init(null, new TrustManager[]{tm}, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

httpClient.getConnectionManager().getSchemeRegistry().register(new Scheme("https", 443, ssf));

2
Просто повторює ту саму помилкову невпевнену нерозв’язаність, про яку вже йшлося у цій темі.
Маркіз Лорнський

-3

Вище було багато відповідей, але я не зміг змусити жодного з них працювати коректно (з моїм обмеженим часом), тому для інших, хто перебуває в тій же ситуації, ви можете спробувати код нижче, який ідеально працював для моїх тестів на тестування Java:

    public static HttpClient wrapClient(HttpClient base) {
    try {
        SSLContext ctx = SSLContext.getInstance("TLS");
        X509TrustManager tm = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { }

            public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { }

            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        ctx.init(null, new TrustManager[]{tm}, null);
        SSLSocketFactory ssf = new SSLSocketFactory(ctx);
        ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        ClientConnectionManager ccm = base.getConnectionManager();
        SchemeRegistry sr = ccm.getSchemeRegistry();
        sr.register(new Scheme("https", ssf, 443));
        return new DefaultHttpClient(ccm, base.getParams());
    } catch (Exception ex) {
        return null;
    }
}

і дзвоніть, як:

DefaultHttpClient baseClient = new DefaultHttpClient();
HttpClient httpClient = wrapClient(baseClient );

Довідка: http://tech.chitgoks.com/2011/04/24/how-to-avoid-javax-net-ssl-sslpeerunverifiedexception-peer-not-authentication-problem-using-apache-httpclient/


Цитуючи EJP: "Просто повторюється той самий помилковий невпевнений нерозв'язок , який уже обговорювався та відхилявся в цій темі" .
jww

-4

Просто використовуйте це -

public DefaultHttpClient wrapClient(HttpClient base) {
    try {
        SSLContext ctx = SSLContext.getInstance("TLS");
        X509TrustManager tm = new X509TrustManager() {
        public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { }

        public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { }

        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    };
    ctx.init(null, new TrustManager[]{tm}, null);
    SSLSocketFactory ssf = new SSLSocketFactory(ctx);
    ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    ClientConnectionManager ccm = base.getConnectionManager();
    SchemeRegistry sr = ccm.getSchemeRegistry();
    sr.register(new Scheme("https", ssf, 443));
    return new DefaultHttpClient(ccm, base.getParams());
} catch (Exception ex) {
    return null;
}
}

Цитуючи EJP: "Просто повторюється той самий помилковий невпевнений нерозв'язок , який уже обговорювався та відхилявся в цій темі" .
jww

-5

Відповідь Даніеля була хорошою, за винятком того, що мені довелося змінити цей код ...

    SchemeRegistry registry = new SchemeRegistry();
    registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    registry.register(new Scheme("https", sf, 443));

    ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

до цього коду ...

    ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
    SchemeRegistry registry = ccm.getShemeRegistry()
    registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    registry.register(new Scheme("https", sf, 443));

щоб змусити його працювати.


5
як це має працювати? ви посилаєтесь на реєстр, перш ніж навіть створили його!
Маттіас Б
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.