Mempercayai semua sertifikat menggunakan HttpClient melalui HTTPS

393

Baru-baru ini diposting pertanyaan mengenai HttpClientoverttp ( ditemukan di sini ). Saya telah membuat beberapa kemajuan, tetapi saya mengalami masalah baru. Seperti masalah terakhir saya, sepertinya saya tidak dapat menemukan contoh di mana saja yang cocok untuk saya. Pada dasarnya, saya ingin klien saya menerima sertifikat apa pun (karena saya hanya menunjuk ke satu server) tetapi saya tetap mendapatkanjavax.net.ssl.SSLException: Not trusted server certificate exception.

Jadi inilah yang saya miliki:


    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);
    }

Dan inilah kesalahan yang saya dapatkan:

    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
harrisonlee
sumber
17
Saya perlu melakukan ini untuk penggunaan internal. Saya benar-benar berharap Anda tidak membiarkan pengguna di luar perusahaan Anda menggunakan aplikasi Anda karena Anda telah membukanya untuk orang dalam serangan tengah dan mereka kemudian akan rentan terhadap seseorang yang membajak sesi mereka. Meskipun demikian, saya perlu melakukan ini sementara untuk beberapa pengujian sampai saya mendapatkan sertifikat nyata di tangan ..... semoga Anda melakukannya untuk alasan sementara yang sama atau aplikasi hanya digunakan secara internal.
Dean Hiller
Saya mencoba solusi ini pada klien http 4.3 apache, tetapi mereka kebanyakan usang. Di sini tidak ada solusi usang: stackoverflow.com/a/18941950/2039471
Alexander Chzhen
Java 1.6 tidak memiliki dukungan SNI yang juga bermasalah dalam skenario ini - jika Anda tidak membangun permintaan dengan benar, Anda bisa mendapatkan sertifikat yang tidak cocok dengan permintaan tersebut. Lihat issues.apache.org/jira/browse/HTTPCLIENT-1119
Bron Davies
2
Pertanyaan ini dikutip dalam makalah The Most Dangerous Code in the World sebagai contoh alasan yang keliru. (makalah penelitian: cs.utexas.edu/~shmat/shmat_ccs12.pdf )
mk_

Jawaban:

421

Catatan: Jangan menerapkan ini dalam kode produksi yang akan Anda gunakan pada jaringan yang tidak sepenuhnya Anda percayai. Terutama apa pun yang terjadi melalui internet publik.

Pertanyaan Anda adalah apa yang ingin saya ketahui. Setelah saya melakukan beberapa pencarian, kesimpulannya adalah sebagai berikut.

Dengan cara HttpClient, Anda harus membuat kelas khusus dari org.apache.http.conn.ssl.SSLSocketFactory, bukan yang org.apache.http.conn.ssl.SSLSocketFactory itu sendiri. Beberapa petunjuk dapat ditemukan di pos ini Penanganan SSL kustom berhenti berfungsi di Android 2.2 FroYo .

Contohnya seperti ...

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();
    }
}

dan gunakan kelas ini saat membuat instance dari 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, tautan di bawah ini untuk seseorang yang mencari solusi HttpURLConnection. Koneksi Https Android

Saya telah menguji dua macam solusi di atas pada froyo, dan semuanya bekerja seperti pesona dalam kasus saya. Akhirnya, menggunakan HttpURLConnection mungkin menghadapi masalah pengalihan, tetapi ini di luar topik.

Catatan: Sebelum Anda memutuskan untuk mempercayai semua sertifikat, Anda mungkin harus mengetahui situs dengan baik dan tidak akan merusaknya bagi pengguna akhir.

Memang, risiko yang Anda ambil harus dipertimbangkan dengan hati-hati, termasuk efek situs tiruan peretas yang disebutkan dalam komentar berikut yang sangat saya hargai. Dalam beberapa situasi, meskipun mungkin sulit untuk mengurus semua sertifikat, Anda sebaiknya mengetahui kelemahan tersirat untuk mempercayai semuanya.

Daniel
sumber
150
jawaban ini mungkin harus dicatat bahwa mempercayai semua sertifikat sangat tidak aman dan membatalkan seluruh tujuan ssl ...
yanokwa
22
@sweeney - Kecuali itu tidak dijamin bahwa Anda berbicara dengan server yang Anda kira. Jika seseorang telah membuat server DNS, Anda bisa mengkomunikasikan kunci enkripsi dengan server peretas.
Richard Szalay
12
@sweeney Dengan kata lain Anda sekarang bertanggung jawab atas serangan man-in-the-middle. Anda juga harus mencatat bahwa kode itu tidak memenuhi spesifikasi: periksa Javadoc. getAcceptedIssuers()tidak diizinkan untuk mengembalikan nol.
Marquis of Lorne
25
-1 Karena itu adalah ide yang buruk untuk menerima semua sertifikat. Sayang sekali bahwa ada begitu banyak blog dan tutorial yang dengan senang hati membimbing pengembang Java di sepanjang jalan melakukan hal yang salah.
Tim Bender
57
+1 Karena saya memerlukan solusi cepat hanya untuk keperluan debugging. Saya tidak akan menggunakan ini dalam produksi karena masalah keamanan yang disebutkan orang lain, tetapi ini adalah persis apa yang saya butuhkan untuk pengujian. Terima kasih!
Danation
495

Pada dasarnya Anda memiliki empat solusi potensial untuk memperbaiki pengecualian "Tidak Tepercaya" di Android menggunakan httpclient:

  1. Percayai semua sertifikat. Jangan lakukan ini, kecuali jika Anda benar-benar tahu apa yang Anda lakukan.
  2. Buat custom SSLSocketFactory yang hanya mempercayai sertifikat Anda. Ini berfungsi selama Anda tahu persis ke server mana Anda akan terhubung, tetapi begitu Anda harus terhubung ke server baru dengan sertifikat SSL yang berbeda, Anda harus memperbarui aplikasi Anda.
  3. Buat file keystore yang berisi "daftar utama" sertifikat Android, lalu tambahkan milik Anda. Jika salah satu sertifikat itu kedaluwarsa, Anda bertanggung jawab untuk memperbaruinya di aplikasi Anda. Saya tidak bisa memikirkan alasan untuk melakukan ini.
  4. Buat custom SSLSocketFactory yang menggunakan KeyStore sertifikat bawaan, tetapi kembali menggunakan KeyStore alternatif untuk apa pun yang gagal memverifikasi dengan default.

Jawaban ini menggunakan solusi # 4, yang menurut saya paling kuat.

Solusinya adalah dengan menggunakan SSLSocketFactory yang dapat menerima beberapa KeyStores, memungkinkan Anda untuk memasok KeyStore Anda sendiri dengan sertifikat Anda sendiri. Ini memungkinkan Anda memuat sertifikat tingkat atas tambahan seperti Thawte yang mungkin hilang pada beberapa perangkat Android. Ini juga memungkinkan Anda untuk memuat sertifikat yang Anda tandatangani sendiri juga. Ini akan menggunakan sertifikat perangkat bawaan bawaan terlebih dahulu, dan kembali pada sertifikat tambahan Anda hanya jika diperlukan.

Pertama, Anda ingin menentukan sertifikat mana yang Anda lewatkan di KeyStore Anda. Jalankan perintah berikut:

openssl s_client -connect www.yourserver.com:443

Dan Anda akan melihat output seperti berikut:

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

Seperti yang Anda lihat, sertifikat root kami dari Thawte. Buka situs web penyedia Anda dan temukan sertifikat yang sesuai. Bagi kami, itu ada di sini , dan Anda dapat melihat bahwa yang kami butuhkan adalah hak cipta 2006.

Jika Anda menggunakan sertifikat yang ditandatangani sendiri, Anda tidak perlu melakukan langkah sebelumnya karena Anda sudah memiliki sertifikat yang ditandatangani.

Kemudian, buat file keystore yang berisi sertifikat penandatanganan yang hilang. Crazybob memiliki detail cara melakukan ini di Android , tetapi idenya adalah melakukan hal berikut:

Jika Anda belum memilikinya, unduh perpustakaan penyedia kastil goyang dari: http://www.bouncycastle.org/latest_releases.html . Ini akan menuju classpath Anda di bawah ini.

Jalankan perintah untuk mengekstrak sertifikat dari server dan membuat file pem. Dalam hal ini, mycert.pem.

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

Kemudian jalankan perintah berikut untuk membuat keystore.

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

Anda akan melihat bahwa skrip di atas menempatkan hasilnya res/raw/mystore.bks. Sekarang Anda memiliki file yang akan Anda muat ke dalam aplikasi Android Anda yang menyediakan sertifikat yang hilang.

Untuk melakukan ini, daftarkan SSLSocketFactory Anda ke skema 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);

Untuk membuat SSLSocketFactory Anda:

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);
    }
}

Dan akhirnya, kode AdditionalKeyStoresSSLSocketFactory, yang menerima KeyStore baru Anda dan memeriksa apakah KeyStore bawaan gagal memvalidasi sertifikat 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
sumber
Hey @emmby, ini sepertinya jawaban yang sempurna untuk masalah saya, tapi saya masih tidak mendapatkan koneksi SSL. Bisakah Anda melihatnya? http://stackoverflow.com/questions/7822381/need-help-understanding-certificate-chains
Matthias B
Terima kasih atas langgan bagus @emmby! Saya terkadang mengalami penundaan yang sangat lama dan kemudian javax.net.ssl.SSLException: Baca kesalahan :. Ada ide? Bagaimana saya dapat menetapkan batas waktu jika solusinya sama dengan stackoverflow.com/questions/5909308/android-2-3-4-ssl-problem ?
Edwin Evans
3
@emmby, dapatkah Anda memberi tahu di mana saya harus meletakkan kode ini untuk mengekspor CLASSPATH = bcprov-jdk16-145.jar CERTSTORE = res / raw / mystore.bks jika [-a $ CERTSTORE]; lalu rm $ CERTSTORE || keluar dari 1 fi keytool \ -import \ -v \ -trustcacerts \ -alias 0 \ -file <(openssl x509 -dalam mycert.pem) \ -keystore $ CERTSTORE \ -storetype BKS \ -provider org.bouncycastle.jce.provider. BouncyCastleProvider \ -providerpath /usr/share/java/bcprov.jar \ -storepass some-password
Rikki Tikki Tavi
1
Hey @emmby. Saya menggunakan solusi Anda di aplikasi saya dan menggunakan sertifikat yang ditandatangani sendiri dari server saya tetapi mendapatkan metode CertificateException () di checkServerTrusted () . Saya mencoba berkomentar bahwa melemparkan pengecualian, dan itu berhasil. jika itu tidak memvalidasi sertifikat server saya maka dapatkah saya menanganinya dengan cara lain, dapatkah Anda memandu apa solusi terbaik dalam kasus ini?
Ankit
7
Ini harus ditandai sebagai jawaban yang benar. Salah satu jawaban paling teliti dan ditulis dengan baik yang pernah saya lihat di SO. Dope
Kachi
74

Tambahkan kode ini sebelum HttpsURLConnectiondan itu akan dilakukan. Saya mendapatkannya.

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(); 
    } 
} 

Saya harap ini membantu Anda.

Alok Gupta
sumber
22
Lihat komentar di atas di bawah jawaban yang diterima. 'Solusi' ini sangat tidak aman.
Marquis of Lorne
5
Ini adalah solusi Q & D yang ideal. Pendek dan "hanya bekerja".
Steve Smith
5
Jawaban sempurna untuk keperluan pengujian !!! Dan ya itu ide yang buruk untuk digunakan dalam produksi, tapi ayolah ... itu harus jelas bagi semua orang yang melihat judul pertanyaan. Itu masih menjawab terbaik / terpendek / dengan tingkat keamanan yang sama (dalam)!
Levite
34

Ini ide yang buruk. Mempercayai sertifikat apa pun hanya (sangat) sedikit lebih baik daripada tidak menggunakan SSL sama sekali. Ketika Anda mengatakan "Saya ingin klien saya menerima sertifikat apa pun (karena saya hanya menunjuk ke satu server)" Anda menganggap ini berarti bahwa entah bagaimana menunjuk ke "satu server" aman, yang bukan pada jaringan publik.

Anda benar-benar terbuka terhadap serangan man-in-the-middle dengan mempercayai sertifikat apa pun. Siapa pun dapat mem-proxy koneksi Anda dengan membuat koneksi SSL terpisah dengan Anda dan dengan server akhir. MITM kemudian memiliki akses ke seluruh permintaan dan respons Anda. Kecuali Anda tidak benar-benar membutuhkan SSL di tempat pertama (pesan Anda tidak memiliki sensitif, dan tidak melakukan otentikasi) Anda tidak boleh mempercayai semua sertifikat secara membabi buta.

Anda harus mempertimbangkan menambahkan sertifikat publik ke jks menggunakan keytool, dan menggunakannya untuk membangun pabrik soket Anda, seperti ini:

    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();

Ini memiliki satu peringatan yang harus diperhatikan. Sertifikat akan berakhir pada akhirnya, dan kode akan berhenti berfungsi pada saat itu. Anda dapat dengan mudah menentukan kapan ini akan terjadi dengan melihat sertifikat.

Dan
sumber
5
Jika Anda tidak menggunakan otentikasi sertifikat-klien, dari sisi klien, Anda tidak perlu manajer kunci (gunakan nulldi SSLContext.init). You should also use the default algorithms (KMF/TMF.getDefaultAlgorithm() ), instead of hard-coding SunX509` (lebih karena default untuk TMF sebenarnya PKIXpada Sun / Oracle JVM)
Bruno
Ada file sertifikat root yang siap digunakan? (seperti browser lakukan)
dani herrera
Dari mana myjks.jksdatangnya?
zionpi
1
@zionpi Dihasilkan menggunakan Java "keytool".
Dan
22

Anda dapat menonaktifkan HttpURLConnection SSL memeriksa untuk tujuan pengujian dengan cara ini sejak 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());
    }
hfmanson
sumber
2
org.apache.http.conn.ssl.AllowAllHostnameVerifiersudah ditinggalkan.
zackygaurav
2
@zackygaurav Menurut javadoc , AllowAllHostnameVerifierdigantikan oleh NoopHostnameVerifier"
DLight
10

API HttpComponents telah berubah. Ini berfungsi dengan kode di bawah ini.

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();
    }
}
Prabhu Periasamy
sumber
Menggunakan strategi kepercayaan khusus adalah jawaban yang tepat. Terima kasih.
Matt Friedman
10

Kode di atas dalam https://stackoverflow.com/a/6378872/1553004 benar, kecuali itu HARUS juga memanggil verifier nama host:

    @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;
}

Saya mendaftar ke stackoverflow secara tegas untuk menambahkan perbaikan ini. Perhatikan peringatan saya!

Robert Blair
sumber
Setelah Anda memverifikasi sertifikat dengan cara ini pada koneksi pertama, apa yang Anda lakukan dengan koneksi selanjutnya? Apakah Anda memanfaatkan pengetahuan yang Anda peroleh dari koneksi pertama? Bagaimana jika sertifikat palsu dengan nama yang sama digunakan pada upaya koneksi 3?
jww
6

Saya menambahkan respons untuk mereka yang menggunakan httpclient-4.5, dan mungkin bekerja untuk 4.4 juga.

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);
    }
}
}
raisercostin
sumber
apa kelas NoopHostnameVerifier () baru?
Mushtakim Ahmed Ansari
1
@MushtakimAhmedAnsari Dari dokumen: "NO_OP HostnameVerifier pada dasarnya mematikan verifikasi nama host. Implementasi ini adalah no-op, dan tidak pernah membuang SSLException."
raisercostin
Terima kasih atas jawaban yang bagus. Yang ini harus mendapat lebih banyak suara.
Abhay Dwivedi
Bagaimana saya menggunakannya? atau apakah Anda menyarankan agar kelas saja akan menggantikan verifikasi sertifikat SSL?
behelit
Iya. httpClient yang digunakan tidak akan memvalidasi sertifikat https
raisercostin
4

Memercayai semua sertifikat bukanlah alternatif nyata bagi saya, jadi saya melakukan yang berikut untuk mendapatkan HttpsURLConnection untuk mempercayai sertifikat baru (lihat juga http://nelenkov.blogspot.jp/2011/12/using-custom-certificate-trust-store- on.html ).

  1. Dapatkan sertifikat; Saya menyelesaikan ini dengan mengekspor sertifikat di Firefox (klik pada ikon kunci kecil, dapatkan detail sertifikat, klik ekspor), lalu gunakan portecle untuk mengekspor truststore (BKS).

  2. Muat Truststore dari /res/raw/geotrust_cert.bks dengan kode berikut:

        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());
koljaTM
sumber
Saya mendapatkan kesalahan ini. IOExceptionjavax.net.ssl.SSLPeerUnverifiedException: No peer certificate. Ini ketika melakukan panggilan eksekusi aktual pada HttpClient setelah pengaturan di atas dilakukan.
Michael
3

Ini adalah versi yang lebih sederhana menggunakan kode httpclient 4.1.2. Ini kemudian dapat dimodifikasi untuk setiap algoritma kepercayaan yang Anda inginkan.

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();
    }
}
Joseph Valerio
sumber
3

Saya melihat respons dari "emmby" (dijawab 16 Jun 11 pada 21:29), item # 4: "Buat custom SSLSocketFactory yang menggunakan KeyStore sertifikat bawaan, tetapi kembali menggunakan KeyStore alternatif untuk apa pun yang gagal untuk memverifikasi dengan default. "

Ini adalah implementasi yang disederhanakan. Muat sistem keystore & gabungkan dengan aplikasi 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();
    }
}

Mode sederhana untuk mengkonversi dari JKS ke 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

* Catatan: Di Android 4.0 (ICS) Trust Store telah berubah, info lebih lanjut: http://nelenkov.blogspot.com.es/2011/12/ics-trust-store-implementation.html

kakek
sumber
3

Bagi mereka yang ingin mengizinkan semua sertifikat bekerja (untuk tujuan pengujian) di atas OAuth, ikuti langkah-langkah ini:

1) Unduh kode sumber API Android OAuth di sini: https://github.com/kaeppler/signpost

2) Temukan file "CommonsHttpOAuthProvider" kelas

3) Ubah seperti di bawah ini:

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" di atas didasarkan pada jawaban yang diterima. Untuk membuatnya lebih mudah, inilah kelas lengkapnya:

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();
    }
}

}

Semoga ini bisa membantu seseorang.

Tiago
sumber
1
Pertanyaannya adalah HttpClientdan HTTPS; bukan OAuth untuk Android dari proyek GitHub.
jww
3

Saya menggunakan ini dan ini bekerja untuk saya di semua OS.

/**
 * 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();
    }
}
Baiju Sharma
sumber
Halo @ yegor256, saya menggunakan kode ini, tetapi masih mendapatkan masalah handshake SSL
user2028
0

Siapa pun yang masih berjuang dengan StartCom SSL Certificates di Android 2.1 kunjungi https://www.startssl.com/certs/ dan unduh ca.pem, sekarang dalam jawaban yang diberikan oleh @emmby ganti

`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`

dengan

 `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`

Harus bekerja di luar kotak. Saya berjuang untuk lebih dari satu hari bahkan setelah jawaban sempurna oleh @emmby .. Semoga ini bisa membantu seseorang ...

13jam
sumber
0

gunakan kelas ini

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;
}

}

Ali Bagheri
sumber
0

masukkan deskripsi gambar di sini

Sspi gagal di xamarin android.

Saya menemukan solusi ini; letakkan kode ini sebelum Anda menekan tautan HTTPS

const SslProtocols _Tls12 = (SslProtocols)0x00000C00;
const SecurityProtocolType Tls12 = (SecurityProtocolType)_Tls12;
ServicePointManager.SecurityProtocol = Tls12;
vinothswami
sumber
-3

bekerja dengan semua 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));
cezarius
sumber
2
Hanya mengulangi non-solusi yang salah dan tidak aman yang telah dibahas dan diberhentikan di utas ini.
Marquis of Lorne
-3

Ada banyak jawaban di atas tetapi saya tidak dapat membuat mereka bekerja dengan benar (dengan waktu terbatas saya), jadi bagi siapa pun yang berada dalam situasi yang sama Anda dapat mencoba kode di bawah ini yang bekerja dengan sempurna untuk tujuan pengujian java saya:

    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;
    }
}

dan panggil seperti:

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

Referensi: http://tech.chitgoks.com/2011/04/24/how-to-avoid-javax-net-ssl-sslpeerunifiedexception-peer-not-authenticated-problem-menggunakan-apache-httpclient/

palsu
sumber
Mengutip EJP: "Hanya mengulangi solusi tidak aman yang salah yang sama yang telah dibahas dan diberhentikan di utas ini" .
jww
-4

Cukup gunakan ini -

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;
}
}
Hemant
sumber
Mengutip EJP: "Hanya mengulangi solusi tidak aman yang salah yang sama yang telah dibahas dan diberhentikan di utas ini" .
jww
-5

Jawaban Daniel baik, kecuali saya harus mengubah kode ini ...

    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);

ke kode ini ...

    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));

untuk membuatnya bekerja.

Dean Hiller
sumber
5
bagaimana seharusnya itu bekerja? Anda merujuk registri sebelum Anda membuatnya!
Matthias B