OkHttp ile tüm sertifikalara güvenmek


111

Test amacıyla, okHttp istemcime bir proxy ayarlandığında her şeye güvenen bir soket fabrikası eklemeye çalışıyorum. Bu defalarca yapıldı, ancak güvenilir bir soket fabrikası uygulamamda bir şey eksik görünüyor:

class TrustEveryoneManager implements 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 null;
    }
}
OkHttpClient client = new OkHttpClient();

final InetAddress ipAddress = InetAddress.getByName("XX.XXX.XXX.XXX"); // some IP
client.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(ipAddress, 8888)));

SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManager[] trustManagers = new TrustManager[]{new TrustEveryoneManager()};
sslContext.init(null, trustManagers, null);
client.setSslSocketFactory(sslContext.getSocketFactory);

Uygulamamdan hiçbir istek gönderilmiyor ve hiçbir istisna kaydedilmiyor, bu nedenle okHttp içinde sessizce başarısız oluyor gibi görünüyor. Daha fazla araştırmanın ardından Connection.upgradeToTls(), el sıkışmaya zorlanırken okHttp'lerde yutulan bir İstisna var gibi görünüyor . Bana verilen istisna:javax.net.ssl.SSLException: SSL handshake terminated: ssl=0x74b522b0: SSL_ERROR_ZERO_RETURN occurred. You should never see this.

Aşağıdaki kod, SSLContextherhangi bir istisna atmayan bir SSLSocketFactory oluştururken bir cazibe gibi çalışan bir kod üretir :

protected SSLContext getTrustingSslContext() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
    final SSLContextBuilder trustingSSLContextBuilder = SSLContexts.custom()
            .loadTrustMaterial(null, new TrustStrategy() {
                @Override
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return true; // Accepts any ssl cert whether valid or not.
                }
            });
    return trustingSSLContextBuilder.build();
}

Sorun şu ki, tüm Apache HttpClient bağımlılıklarını uygulamamdan tamamen kaldırmaya çalışıyorum. Apache HttpClient'in temelini oluşturan kod SSLContextyeterince basit görünüyor, ancak açıkçası kendimi SSLContextbuna uyacak şekilde yapılandıramadığım için bir şeyi kaçırıyorum .

Benim istediğimi Apache HttpClient kullanmadan yapan bir SSLContext uygulaması üretebilecek olan var mı?


2
"Test amacıyla, okHttp istemcime her şeye güvenen bir soket fabrikası eklemeye çalışıyorum" - bunun en başta iyi bir fikir olduğunu düşünmenize neden olan nedir?
CommonsWare

1
Sadece tamamen güvendiğim bir ağdan çağrılıyor.
seato

Bu ajava.net.SocketTimeoutException: Read timed out
IgorGanapolsky

Yanıtlar:


250

Birinin buraya düşmesi durumunda, benim için işe yarayan (tek) çözüm buradaOkHttpClient açıklanan benzerini yaratmaktır .

İşte kod:

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, (X509TrustManager)trustAllCerts[0]);
    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);
  }
}

15
Neden SSLve değil TLS?
IgorGanapolsky

1
Bunun için çok teşekkürler! Güçlendirme ile ilgili dokümantasyon (okhttp kullanır) eksik, bu tür kod örnekleri beni defalarca çok fazla zaman kazandırıyor.
Warpzit

8
Bu yaklaşımın artık OkHttp'nin mevcut sürümlerinde çalışmadığını unutmayın. 3.1.1 ile tamamen bozuk görünüyor. 3.1.2'den itibaren, X509TrustManager.getAcceptedIssuers()yerine boş bir dizi döndürmelidir null. Daha fazla bilgi için bu işleme bakın (aşağı kaydırın ve RealTrustRootIndex.java altındaki notlara bakın).
jbxbergdev

12
Bunu denedim, ama yine de Handshake failedistisna oluyorum . Baska öneri?
Esteban


13

Aşağıdaki yöntem kullanımdan kaldırılmıştır

sslSocketFactory(SSLSocketFactory sslSocketFactory)

Olarak güncellemeyi düşünün

sslSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager)

13

OkHttp 3.0'ı güncelleyin, getAcceptedIssuers()işlev yerine boş bir dizi döndürmelidir null.


2
@Override public X509Certificate [] getAcceptedIssuers () {return new X509Certificate [] {}; // StackOverflow}
Ervin Zhang,

11

SSLSocketFactory, OkHttp'nin temiz bir sertifika zinciri oluşturmak için ihtiyaç duyduğu bir alan olan X509TrustManager'ını açığa çıkarmaz. Bu yöntem, güven yöneticisini çıkarmak için bunun yerine yansıma kullanmalıdır. Uygulamalar sslSocketFactory'yi (SSLSocketFactory, X509TrustManager) çağırmayı tercih etmelidir, bu da böyle bir yansımayı önler.

Kaynak: OkHttp belgeleri

OkHttpClient.Builder builder = new OkHttpClient.Builder();

builder.sslSocketFactory(sslContext.getSocketFactory(),
    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[]{};
        }
    });

Bu, kendinden imzalı sertifikalar için işe yaramaz. 401 Yetkisiz hataya neden olur .
IgorGanapolsky

5
Nereden sslContextgeliyor?
Anonsage

3
Nasıl başlatırsınız sslContext?
kiltek

10

İhtiyaç duyan varsa, bu sonxurxo'nun Kotlin'deki çözümüdür.

private fun getUnsafeOkHttpClient(): OkHttpClient {
    // Create a trust manager that does not validate certificate chains
    val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
        override fun checkClientTrusted(chain: Array<out X509Certificate>?, authType: String?) {
        }

        override fun checkServerTrusted(chain: Array<out X509Certificate>?, authType: String?) {
        }

        override fun getAcceptedIssuers() = arrayOf<X509Certificate>()
    })

    // Install the all-trusting trust manager
    val sslContext = SSLContext.getInstance("SSL")
    sslContext.init(null, trustAllCerts, java.security.SecureRandom())
    // Create an ssl socket factory with our all-trusting manager
    val sslSocketFactory = sslContext.socketFactory

    return OkHttpClient.Builder()
        .sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager)
        .hostnameVerifier { _, _ -> true }.build()
}

7

Kotlin için bir uzatma fonksiyonu yaptım. İstediğiniz yere yapıştırın ve oluştururken içe aktarın OkHttpClient.

fun OkHttpClient.Builder.ignoreAllSSLErrors(): OkHttpClient.Builder {
    val naiveTrustManager = object : X509TrustManager {
        override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
        override fun checkClientTrusted(certs: Array<X509Certificate>, authType: String) = Unit
        override fun checkServerTrusted(certs: Array<X509Certificate>, authType: String) = Unit
    }

    val insecureSocketFactory = SSLContext.getInstance("TLSv1.2").apply {
        val trustAllCerts = arrayOf<TrustManager>(naiveTrustManager)
        init(null, trustAllCerts, SecureRandom())
    }.socketFactory

    sslSocketFactory(insecureSocketFactory, naiveTrustManager)
    hostnameVerifier(HostnameVerifier { _, _ -> true })
    return this
}

şu şekilde kullanın:

val okHttpClient = OkHttpClient.Builder().apply {
    // ...
    if (BuildConfig.DEBUG) //if it is a debug build ignore ssl errors
        ignoreAllSSLErrors()
    //...
}.build()

Aslında bunu şu şekilde kullanabilirsiniz: OkHttpClient.Builder () .ignoreAllSSLErrors () .connectTimeout (api.timeout, TimeUnit.SECONDS) .writeTimeout (api.timeout, TimeUnit.SECONDS) vb., Sonuçta bir oluşturucu kalıbı
Emanuel Moecklin

1

İhtiyaç duyan varsa bu Scala çözümüdür

def anUnsafeOkHttpClient(): OkHttpClient = {
val manager: TrustManager =
  new X509TrustManager() {
    override def checkClientTrusted(x509Certificates: Array[X509Certificate], s: String) = {}

    override def checkServerTrusted(x509Certificates: Array[X509Certificate], s: String) = {}

    override def getAcceptedIssuers = Seq.empty[X509Certificate].toArray
  }
val trustAllCertificates =  Seq(manager).toArray

val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCertificates, new java.security.SecureRandom())
val sslSocketFactory = sslContext.getSocketFactory()
val okBuilder = new OkHttpClient.Builder()
okBuilder.sslSocketFactory(sslSocketFactory, trustAllCertificates(0).asInstanceOf[X509TrustManager])
okBuilder.hostnameVerifier(new NoopHostnameVerifier)
okBuilder.build()

}


-12

Kodda sertifika doğrulamasını asla geçersiz kılmaya çalışmamalısınız! Test yapmanız gerekiyorsa, bir dahili / test CA kullanın ve cihaza veya emülatöre CA kök sertifikasını yükleyin. CA’yı nasıl kuracağınızı bilmiyorsanız BurpSuite veya Charles Proxy’i kullanabilirsiniz.


37
Ah, hadi ama. Ya bir şirket için çalışıyorsanız ve sizi VPN aracılığıyla HTTPS sunucularına bağlanmaya zorluyorsa? Bunu bir testte nasıl simüle edeceksiniz?
IgorGanapolsky

5
Ya bu en saf domuz yıkama. Bunu sadece test yapılarında derliyoruz, bu yüzden tehlike yok.
Adam
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.