web-dev-qa-db-ger.com

Deaktivieren Sie die SSL-Zertifikatüberprüfung in der Retrofit-Bibliothek

Ich verwende Retrofit in Android, um mich mit dem Server zu verbinden.

public class ApiClient {
    public static final String BASE_URL = "https://example.com/";
    private static Retrofit retrofit = null;

    public static Retrofit getClient() {
        if (retrofit==null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return retrofit;
    }
}

Das ist mein dev. Server und ich möchte die Zertifikatprüfung deaktivieren. Wie kann ich diesen Code implementieren?

FEHLER: javax.net.ssl.SSLHandshakeException: Java.security.cert.CertPathValidatorException: Vertrauensanker für Zertifizierungspfad nicht gefunden.

8
Ronak Patel

Verwenden Sie diese Klasse, um eine unsichere Retrofit-Instanz abzurufen. Ich habe Importe eingeschlossen, um Verwirrung zu vermeiden.

import Java.security.cert.CertificateException;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import view.utils.AppConstants;

/**
 * Created by Hitesh.Sahu on 11/23/2016.
 */

public class NetworkHandler {

    public static Retrofit getRetrofit() {

        return new Retrofit.Builder()
                .baseUrl(AppConstants.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .client(getUnsafeOkHttpClient())
                .build();
    }


    private static OkHttpClient getUnsafeOkHttpClient() {
        try {
            // Create a trust manager that does not validate certificate chains
            final TrustManager[] trustAllCerts = new TrustManager[] {
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(Java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                        }

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

                        @Override
                        public Java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new Java.security.cert.X509Certificate[]{};
                        }
                    }
            };

            // Install the all-trusting trust manager
            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new Java.security.SecureRandom());
            // Create an ssl socket factory with our all-trusting manager
            final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.sslSocketFactory(sslSocketFactory);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });

            OkHttpClient okHttpClient = builder.build();
            return okHttpClient;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

Und dann einfach Retrofit ohne ssl check verwenden

    private void postFeedbackOnServer() {

        MyApiEndpointInterface apiService =
                NetworkHandler.getRetrofit().create(MyApiEndpointInterface.class);

        Call<ResponseBE> call = apiService.submitFeedbackToServer(requestObject);

        Log.e(TAG ,  "Request is" + new Gson().toJson(requestObject).toString() );

        call.enqueue(new Callback<ResponseBE>() {
            @Override
            public void onResponse(Call<ResponseBE> call, Response<ResponseBE> response) {
                int statusCode = response.code();

                if (statusCode == HttpURLConnection.HTTP_OK) {

              ......

                } else {
                    Toast.makeText(FeedbackActivity.this, "Failed to submit Data" + statusCode, Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onFailure(Call<ResponseBE> call, Throwable t) {

                // Log error here since request failed
                Toast.makeText(FeedbackActivity.this, "Failure" + t.getLocalizedMessage(), Toast.LENGTH_SHORT).show();

            }
        });
    }
24
Hitesh Sahu

Ich rate dringend davon ab, dies zu tun

Kurze Antwort - Unterklasse HostNameVerifier, override verify (), um immer true zurückzugeben.

Dies hat bessere Optionen

Lange Antwort - schau mal in meinem (ziemlich alt werdenden) Blog nach: Android und SSL zusammenarbeiten lassen

Vielleicht die beste Option für Ihr Szenario

Legen Sie das https für Ihren Testserver in http ab, dann muss sich die Logik nicht ändern.

HTH

4
The_GM

IMO können Sie Googles Dokumentation - Sicherheit mit HTTPS und SSL lesen.

Wenn Sie Beispielcode für die Verwendung von Retrofit mit Ihrem selbstsignierten Zertifikat verwenden möchten, versuchen Sie Folgendes: Ich hoffe, es hilft!

...
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    try{
        OkHttpClient client = new OkHttpClient.Builder()
                .sslSocketFactory(getSSLSocketFactory())
                .hostnameVerifier(getHostnameVerifier())
                .build();

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(API_URL_BASE)
                .addConverterFactory(GsonConverterFactory.create())
                .client(client)
                .build();

        WebAPIService service = retrofit.create(WebAPIService.class);

        Call<JsonObject> jsonObjectCall = service.getData(...);
        ...
    } catch (Exception e) {
        e.printStackTrace();
    }
}

// for SSL...    
// Read more at https://developer.Android.com/training/articles/security-ssl.html#CommonHostnameProbs
private HostnameVerifier getHostnameVerifier() {
    return new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true; // verify always returns true, which could cause insecure network traffic due to trusting TLS/SSL server certificates for wrong hostnames
            //HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
            //return hv.verify("localhost", session);
        }
    };
}        

private TrustManager[] getWrappedTrustManagers(TrustManager[] trustManagers) {
    final X509TrustManager originalTrustManager = (X509TrustManager) trustManagers[0];
    return new TrustManager[]{
            new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return originalTrustManager.getAcceptedIssuers();
                }

                public void checkClientTrusted(X509Certificate[] certs, String authType) {
                    try {
                        if (certs != null && certs.length > 0){
                            certs[0].checkValidity();
                        } else {
                            originalTrustManager.checkClientTrusted(certs, authType);
                        }
                    } catch (CertificateException e) {
                        Log.w("checkClientTrusted", e.toString());
                    }
                }

                public void checkServerTrusted(X509Certificate[] certs, String authType) {
                    try {
                        if (certs != null && certs.length > 0){
                            certs[0].checkValidity();
                        } else {
                            originalTrustManager.checkServerTrusted(certs, authType);
                        }
                    } catch (CertificateException e) {
                        Log.w("checkServerTrusted", e.toString());
                    }
                }
            }
    };
}

private SSLSocketFactory getSSLSocketFactory()
        throws CertificateException, KeyStoreException, IOException,
        NoSuchAlgorithmException, KeyManagementException {
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    InputStream caInput = getResources().openRawResource(R.raw.your_cert); // File path: app\src\main\res\raw\your_cert.cer
    Certificate ca = cf.generateCertificate(caInput);
    caInput.close();
    KeyStore keyStore = KeyStore.getInstance("BKS");
    keyStore.load(null, null);
    keyStore.setCertificateEntry("ca", ca);
    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
    tmf.init(keyStore);
    TrustManager[] wrappedTrustManagers = getWrappedTrustManagers(tmf.getTrustManagers());
    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, wrappedTrustManagers, null);
    return sslContext.getSocketFactory();
}
...
4
BNK

Die Syntax hat sich ein wenig geändert, seit Hitesh Sahus Antwort veröffentlicht wurde. Jetzt können Sie Lambdas für einige der Methoden verwenden, einige Wurfklauseln entfernen und Methodenaufrufe der Kettenerstellungsmethode entfernen.

private static OkHttpClient createOkHttpClient() {
    try {
        final TrustManager[] trustAllCerts = new TrustManager[] {
                new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(Java.security.cert.X509Certificate[] chain, String authType) {}

                    @Override
                    public void checkServerTrusted(Java.security.cert.X509Certificate[] chain, String authType) {}

                    @Override
                    public Java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        return new Java.security.cert.X509Certificate[]{};
                    }
                }
        };
        final SSLContext sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null, trustAllCerts, new Java.security.SecureRandom());
        return new OkHttpClient.Builder()
                .sslSocketFactory(sslContext.getSocketFactory())
                .hostnameVerifier((hostname, session) -> true)
                .build();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
1
whirlwin

Die Implementierung einer solchen Problemumgehung in Code, auch zu Testzwecken, ist eine schlechte Praxis.

Sie können:

  1. Generieren Sie Ihre Zertifizierungsstelle.
  2. Unterschreiben Sie Ihr Zertifikat bei CA.
  3. Fügen Sie Ihre Zertifizierungsstelle als vertrauenswürdig hinzu.

Einige Links, die nützlich sein können:

0
mwo
private boolean bypassSSLVerification = true;
private boolean privateCA = false;



if(bypassSSLVerification)
            {
                IO.setDefaultSSLContext(SSLContextManager.getTrustAllSSLContext());
                IO.setDefaultHostnameVerifier(new HostnameVerifier()
                {
                    @Override
                    public boolean verify(String s, SSLSession sslSession)
                    {
                        return true;
                    }
                });
            }
            else if(privateCA)
            {
                IO.setDefaultSSLContext(SSLContextManager.getSSLContext(context));
            }

SSLContextManager.Java

    public class SSLContextManager
{
    public static SSLContext getSSLContext(Context context) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, KeyManagementException, NoSuchProviderException
    {
        // Load CAs from an InputStream
        CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
        InputStream cert = context.getResources().openRawResource(R.raw.my_cert); // Place your 'my_cert.crt' file in `res/raw`
        Certificate ca;
        try
        {
            ca = cf.generateCertificate(cert);
        }
        finally
        {
            cert.close();
        }

        // Create a KeyStore containing our trusted CAs
        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);

        // Create a TrustManager that trusts the CAs in our KeyStore
        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);

        // Create an SSLContext that uses our TrustManager
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, tmf.getTrustManagers(), null);

        return sslContext;
    }

    public static SSLContext getTrustAllSSLContext() throws NoSuchAlgorithmException, KeyManagementException
    {
        // Create a trust manager that does not validate certificate chains
        final TrustManager[] trustAllCerts = new TrustManager[] {
                new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(Java.security.cert.X509Certificate[] chain, String authType) {
                    }

                    @Override
                    public void checkServerTrusted(Java.security.cert.X509Certificate[] chain, String authType){
                    }

                    @Override
                    public Java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        return new Java.security.cert.X509Certificate[]{};
                    }
                }
        };

        // Install the all-trusting trust manager
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, trustAllCerts, new Java.security.SecureRandom());

        return sslContext;
    }
}
0
M.Saad Lakhan