kotlin 在改造库中禁用SSL证书检查

dldeef67  于 2023-03-24  发布在  Kotlin
关注(0)|答案(7)|浏览(197)

我在android中使用reflect来连接服务器。

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

这是我的开发服务器,我想禁用证书检查。我如何在此代码中实现?
错误:javax.net.ssl.SSLHandshakeException:证书路径验证器异常:找不到证书路径的信任锚。

thtygnil

thtygnil1#

使用我从Trusting all certificates with okHttp的答案中复制的这个类来获取不安全的Retrofit示例:

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;

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

然后简单地使用reflect而不进行ssl检查,如下所示:

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

        }
    });
}
csga3l58

csga3l582#

自Hitesh Sahu的答案发布以来,语法发生了一些变化。现在您可以对一些方法使用lambdas,删除一些throw子句和chain builder方法调用。

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

pn9klfpd3#

在我的例子中,我用Kotlin解决了这个问题:

object Instance {

    private const val BASE_URL: String = "https://base_url/"

    val service: Service by lazy {
        Retrofit
            .Builder()
            .baseUrl(BASE_URL)
            .client(getUnsafeOkHttpClient())
            .build().create(Service::class.java)
    }
    private fun getUnsafeOkHttpClient(): OkHttpClient? {
        return try {
            // Create a trust manager that does not validate certificate chains
            val trustAllCerts = arrayOf<TrustManager>(
                object : X509TrustManager {
                    @Throws(CertificateException::class)
                    override fun checkClientTrusted(
                        chain: Array<X509Certificate?>?,
                        authType: String?
                    ) {
                    }

                    @Throws(CertificateException::class)
                    override fun checkServerTrusted(
                        chain: Array<X509Certificate?>?,
                        authType: String?
                    ) {
                    }

                    override fun getAcceptedIssuers(): Array<X509Certificate?>? {
                        return arrayOf()
                    }
                }
            )

            // Install the all-trusting trust manager
            val sslContext = SSLContext.getInstance("SSL")
            sslContext.init(null, trustAllCerts, SecureRandom())
            // Create an ssl socket factory with our all-trusting manager
            val sslSocketFactory = sslContext.socketFactory
            val trustManagerFactory: TrustManagerFactory =
                TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
            trustManagerFactory.init(null as KeyStore?)
            val trustManagers: Array<TrustManager> =
                trustManagerFactory.trustManagers
            check(!(trustManagers.size != 1 || trustManagers[0] !is X509TrustManager)) {
                "Unexpected default trust managers:" + trustManagers.contentToString()
            }

            val trustManager =
                trustManagers[0] as X509TrustManager

            val builder = OkHttpClient.Builder()
            builder.sslSocketFactory(sslSocketFactory, trustManager)
            builder.hostnameVerifier(HostnameVerifier { _, _ -> true })
            builder.build()
        } catch (e: Exception) {
            throw RuntimeException(e)
        }
    }
}
2ekbmq32

2ekbmq324#

IMO,你可以读Google's documentation - Security with HTTPS and SSL
关于使用Retrofit与您的自签名证书的示例代码,请尝试以下操作,希望对您有帮助!

...
@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();
}
...
2admgd59

2admgd595#

我在这个页面上尝试了@whirlwin的解决方案,但在java 9+中不起作用。一些小的变化导致了这样的结果:

private static OkHttpClient createTrustingOkHttpClient() {
    try {
        X509TrustManager x509TrustManager = 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 TrustManager[] trustAllCerts = new TrustManager[] {
                x509TrustManager
        };
        final SSLContext sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
        return new OkHttpClient.Builder()
                .sslSocketFactory(sslContext.getSocketFactory(), x509TrustManager)
                .hostnameVerifier((hostname, session) -> true)
                .build();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

你可以想象,这对我很有效。快乐的日子!尽管如此,使用这个时要小心。

ix0qys7i

ix0qys7i6#

根据@Hitesh Sahu的回答,在Kotlin中添加代码:

fun getRetrofirApiService(currentBaseURL: String): YourAPIService{
    val TIMEOUT = 2L
    val logging = HttpLoggingInterceptor()
    logging.setLevel(HttpLoggingInterceptor.Level.BODY)

    val retrofit = Retrofit.Builder()
        .baseUrl(currentBaseURL)
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .addConverterFactory(NullOnEmptyConverterFactory())
        .addConverterFactory(GsonConverterFactory.create())
        .client(createOkHttpClient())
        .build()
    return retrofit.create(APIService::class.java)
}

现在创建Http客户端,如下所示:

private fun createOkHttpClient(): OkHttpClient {
    return try {
        val trustAllCerts: Array<TrustManager> = arrayOf(MyManager())
        val sslContext = SSLContext.getInstance("SSL")
        sslContext.init(null, trustAllCerts, SecureRandom())
        val logging = HttpLoggingInterceptor()
        logging.level = HttpLoggingInterceptor.Level.BODY
        OkHttpClient.Builder()
            .sslSocketFactory(sslContext.getSocketFactory())
            .addInterceptor(logging)
            .hostnameVerifier { hostname: String?, session: SSLSession? -> true }
            .build()
    } catch (e: Exception) {
        throw RuntimeException(e)
    }
}

MyManager类如下所示:

class MyManager : X509TrustManager {

    override fun checkServerTrusted(
        p0: Array<out java.security.cert.X509Certificate>?,
        p1: String?
    ) {
        //allow all
    }

    override fun checkClientTrusted(
        p0: Array<out java.security.cert.X509Certificate>?,
        p1: String?
    ) {
        //allow all
    }

    override fun getAcceptedIssuers(): Array<java.security.cert.X509Certificate> {
        return arrayOf()
    }
}

相同的进口如下所示:

import okhttp3.MediaType
    import okhttp3.OkHttpClient
    import okhttp3.RequestBody
    import okhttp3.logging.HttpLoggingInterceptor
    import retrofit2.Retrofit
    import retrofit2.adapter.rxjava2.Result
    import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
    import retrofit2.converter.gson.GsonConverterFactory
    import java.security.SecureRandom
    import java.util.concurrent.TimeUnit
    import javax.net.ssl.SSLContext
    import javax.net.ssl.SSLSession
    import javax.net.ssl.TrustManager
    import javax.net.ssl.X509TrustManager
6psbrbz9

6psbrbz97#

在代码中实现这种变通方法,即使是为了测试目的,也是一种不好的做法。
您可以:
1.生成CA。
1.使用CA签署证书。
1.将CA添加为受信任CA。
一些可能有用的链接:

相关问题