Javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL anlaşması iptal edildi: SSL kitaplığında hata, genellikle bir protokol hatası


103

Aşağıdaki kodu android'de çalıştırmaya çalışıyorum

URLConnection l_connection = null;
        // Create connection
        uzip=new UnZipData(mContext);
        l_url = new URL(serverurl);

        if ("https".equals(l_url.getProtocol())) {
            System.out.println("<<<<<<<<<<<<< Before TLS >>>>>>>>>>>>");
            sslcontext = SSLContext.getInstance("TLS");
            System.out.println("<<<<<<<<<<<<< After TLS >>>>>>>>>>>>");
            sslcontext.init(null,
                    new TrustManager[] { new CustomTrustManager()},
                    new java.security.SecureRandom());
            HttpsURLConnection
                    .setDefaultHostnameVerifier(new CustomHostnameVerifier());
            HttpsURLConnection.setDefaultSSLSocketFactory(sslcontext
                    .getSocketFactory());

            l_connection = (HttpsURLConnection) l_url.openConnection();
            ((HttpsURLConnection) l_connection).setRequestMethod("POST");
        } else {
            l_connection = (HttpURLConnection) l_url.openConnection();
            ((HttpURLConnection) l_connection).setRequestMethod("POST");
        }
        /*System.setProperty("http.agent", "Android_Phone");*/


        l_connection.setConnectTimeout(10000);
        l_connection.setRequestProperty("Content-Language", "en-US");
        l_connection.setUseCaches(false);
        l_connection.setDoInput(true);
        l_connection.setDoOutput(true);
        System.out.println("<<<<<<<<<<<<< Before Connection >>>>>>>>>>>>");
        l_connection.connect();

On l_connection.connect(), bu SSLhandshakeException'ı veriyor. Bazen işe yarıyor, ancak çoğu zaman istisna veriyor. Sadece Android 4.0 emülatöründe oluyor. Android 4.4 ve 5.0'da test ettim, iyi çalışıyor. Bunun nedeni ne olabilir? Lütfen yardım et

YIĞIN İZLEME

    04-28 15:51:13.143: W/System.err(2915): javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x870c918: Failure in SSL library, usually a protocol error
04-28 15:51:13.143: W/System.err(2915): error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:658 0xb7c393a1:0x00000000)
04-28 15:51:13.143: W/System.err(2915):     at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:460)
04-28 15:51:13.143: W/System.err(2915):     at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:257)
04-28 15:51:13.143: W/System.err(2915):     at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:210)
04-28 15:51:13.143: W/System.err(2915):     at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:477)
04-28 15:51:13.153: W/System.err(2915):     at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:441)
04-28 15:51:13.153: W/System.err(2915):     at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:282)
04-28 15:51:13.153: W/System.err(2915):     at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:232)
04-28 15:51:13.153: W/System.err(2915):     at libcore.net.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:80)
04-28 15:51:13.153: W/System.err(2915):     at libcore.net.http.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:164)
04-28 15:51:13.153: W/System.err(2915):     at com.ofss.fcdb.mobile.android.rms.helpers.NetworkConnector.getConnection(NetworkConnector.java:170)
04-28 15:51:13.153: W/System.err(2915):     at com.ofss.fcdb.mobile.android.rms.util.InitiateRMS$2.run(InitiateRMS.java:221)
04-28 15:51:13.153: W/System.err(2915):     at java.lang.Thread.run(Thread.java:856)
04-28 15:51:13.153: W/System.err(2915): Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x870c918: Failure in SSL library, usually a protocol error
04-28 15:51:13.153: W/System.err(2915): error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:658 0xb7c393a1:0x00000000)
04-28 15:51:13.153: W/System.err(2915):     at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(Native Method)
04-28 15:51:13.153: W/System.err(2915):     at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:410)
04-28 15:51:13.153: W/System.err(2915):     ... 11 more
04-28 16:42:44.139: W/ResourceType(3140): No package identifier when getting value for resource number 0x00000000

uygulamanızı gerçek cihazda kontrol ettiniz mi?
Paresh Mayani

Hangi istisnayı veriyor? Yığın izleme?
Lorne Markisi

@PareshMayani Evet, Android 4.0'a sahip gerçek bir cihazda bile istisna gösteriyor.
Bhavit S. Sengar

@EJP Soruyu güncelledim, stacktrace eklendi.
Bhavit S. Sengar

Bu sadece soru jelibon etiketledi. Android-4.2-jelly-bean mi demek istediniz ?
Daniel Daranas

Yanıtlar:


121

Wireshark kullanarak veri paketlerini analiz ederek çözüm buldum. Ne buldum güvenli bir bağlantı yapma android için geri düşerken olmasıdır SSLv3 dan TLSv1 . Bu, 4.4'ün altındaki android sürümlerinde bir hatadır ve SSLv3 protokolü Etkin Protokoller listesinden kaldırılarak çözülebilir. NoSSLv3SocketFactory.java adında özel bir socketFactory sınıfı yaptım. Bir priz fabrikası yapmak için bunu kullanın.

/*Copyright 2015 Bhavit Singh Sengar
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.*/

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;


public class NoSSLv3SocketFactory extends SSLSocketFactory{
    private final SSLSocketFactory delegate;

public NoSSLv3SocketFactory() {
    this.delegate = HttpsURLConnection.getDefaultSSLSocketFactory();
}

public NoSSLv3SocketFactory(SSLSocketFactory delegate) {
    this.delegate = delegate;
}

@Override
public String[] getDefaultCipherSuites() {
    return delegate.getDefaultCipherSuites();
}

@Override
public String[] getSupportedCipherSuites() {
    return delegate.getSupportedCipherSuites();
}

private Socket makeSocketSafe(Socket socket) {
    if (socket instanceof SSLSocket) {
        socket = new NoSSLv3SSLSocket((SSLSocket) socket);
    }
    return socket;
}

@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
    return makeSocketSafe(delegate.createSocket(s, host, port, autoClose));
}

@Override
public Socket createSocket(String host, int port) throws IOException {
    return makeSocketSafe(delegate.createSocket(host, port));
}

@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
    return makeSocketSafe(delegate.createSocket(host, port, localHost, localPort));
}

@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
    return makeSocketSafe(delegate.createSocket(host, port));
}

@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
    return makeSocketSafe(delegate.createSocket(address, port, localAddress, localPort));
}

private class NoSSLv3SSLSocket extends DelegateSSLSocket {

    private NoSSLv3SSLSocket(SSLSocket delegate) {
        super(delegate);

    }

    @Override
    public void setEnabledProtocols(String[] protocols) {
        if (protocols != null && protocols.length == 1 && "SSLv3".equals(protocols[0])) {

            List<String> enabledProtocols = new ArrayList<String>(Arrays.asList(delegate.getEnabledProtocols()));
            if (enabledProtocols.size() > 1) {
                enabledProtocols.remove("SSLv3");
                System.out.println("Removed SSLv3 from enabled protocols");
            } else {
                System.out.println("SSL stuck with protocol available for " + String.valueOf(enabledProtocols));
            }
            protocols = enabledProtocols.toArray(new String[enabledProtocols.size()]);
        }

        super.setEnabledProtocols(protocols);
    }
}

public class DelegateSSLSocket extends SSLSocket {

    protected final SSLSocket delegate;

    DelegateSSLSocket(SSLSocket delegate) {
        this.delegate = delegate;
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return delegate.getSupportedCipherSuites();
    }

    @Override
    public String[] getEnabledCipherSuites() {
        return delegate.getEnabledCipherSuites();
    }

    @Override
    public void setEnabledCipherSuites(String[] suites) {
        delegate.setEnabledCipherSuites(suites);
    }

    @Override
    public String[] getSupportedProtocols() {
        return delegate.getSupportedProtocols();
    }

    @Override
    public String[] getEnabledProtocols() {
        return delegate.getEnabledProtocols();
    }

    @Override
    public void setEnabledProtocols(String[] protocols) {
        delegate.setEnabledProtocols(protocols);
    }

    @Override
    public SSLSession getSession() {
        return delegate.getSession();
    }

    @Override
    public void addHandshakeCompletedListener(HandshakeCompletedListener listener) {
        delegate.addHandshakeCompletedListener(listener);
    }

    @Override
    public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) {
        delegate.removeHandshakeCompletedListener(listener);
    }

    @Override
    public void startHandshake() throws IOException {
        delegate.startHandshake();
    }

    @Override
    public void setUseClientMode(boolean mode) {
        delegate.setUseClientMode(mode);
    }

    @Override
    public boolean getUseClientMode() {
        return delegate.getUseClientMode();
    }

    @Override
    public void setNeedClientAuth(boolean need) {
        delegate.setNeedClientAuth(need);
    }

    @Override
    public void setWantClientAuth(boolean want) {
        delegate.setWantClientAuth(want);
    }

    @Override
    public boolean getNeedClientAuth() {
        return delegate.getNeedClientAuth();
    }

    @Override
    public boolean getWantClientAuth() {
        return delegate.getWantClientAuth();
    }

    @Override
    public void setEnableSessionCreation(boolean flag) {
        delegate.setEnableSessionCreation(flag);
    }

    @Override
    public boolean getEnableSessionCreation() {
        return delegate.getEnableSessionCreation();
    }

    @Override
    public void bind(SocketAddress localAddr) throws IOException {
        delegate.bind(localAddr);
    }

    @Override
    public synchronized void close() throws IOException {
        delegate.close();
    }

    @Override
    public void connect(SocketAddress remoteAddr) throws IOException {
        delegate.connect(remoteAddr);
    }

    @Override
    public void connect(SocketAddress remoteAddr, int timeout) throws IOException {
        delegate.connect(remoteAddr, timeout);
    }

    @Override
    public SocketChannel getChannel() {
        return delegate.getChannel();
    }

    @Override
    public InetAddress getInetAddress() {
        return delegate.getInetAddress();
    }

    @Override
    public InputStream getInputStream() throws IOException {
        return delegate.getInputStream();
    }

    @Override
    public boolean getKeepAlive() throws SocketException {
        return delegate.getKeepAlive();
    }

    @Override
    public InetAddress getLocalAddress() {
        return delegate.getLocalAddress();
    }

    @Override
    public int getLocalPort() {
        return delegate.getLocalPort();
    }

    @Override
    public SocketAddress getLocalSocketAddress() {
        return delegate.getLocalSocketAddress();
    }

    @Override
    public boolean getOOBInline() throws SocketException {
        return delegate.getOOBInline();
    }

    @Override
    public OutputStream getOutputStream() throws IOException {
        return delegate.getOutputStream();
    }

    @Override
    public int getPort() {
        return delegate.getPort();
    }

    @Override
    public synchronized int getReceiveBufferSize() throws SocketException {
        return delegate.getReceiveBufferSize();
    }

    @Override
    public SocketAddress getRemoteSocketAddress() {
        return delegate.getRemoteSocketAddress();
    }

    @Override
    public boolean getReuseAddress() throws SocketException {
        return delegate.getReuseAddress();
    }

    @Override
    public synchronized int getSendBufferSize() throws SocketException {
        return delegate.getSendBufferSize();
    }

    @Override
    public int getSoLinger() throws SocketException {
        return delegate.getSoLinger();
    }

    @Override
    public synchronized int getSoTimeout() throws SocketException {
        return delegate.getSoTimeout();
    }

    @Override
    public boolean getTcpNoDelay() throws SocketException {
        return delegate.getTcpNoDelay();
    }

    @Override
    public int getTrafficClass() throws SocketException {
        return delegate.getTrafficClass();
    }

    @Override
    public boolean isBound() {
        return delegate.isBound();
    }

    @Override
    public boolean isClosed() {
        return delegate.isClosed();
    }

    @Override
    public boolean isConnected() {
        return delegate.isConnected();
    }

    @Override
    public boolean isInputShutdown() {
        return delegate.isInputShutdown();
    }

    @Override
    public boolean isOutputShutdown() {
        return delegate.isOutputShutdown();
    }

    @Override
    public void sendUrgentData(int value) throws IOException {
        delegate.sendUrgentData(value);
    }

    @Override
    public void setKeepAlive(boolean keepAlive) throws SocketException {
        delegate.setKeepAlive(keepAlive);
    }

    @Override
    public void setOOBInline(boolean oobinline) throws SocketException {
        delegate.setOOBInline(oobinline);
    }

    @Override
    public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
        delegate.setPerformancePreferences(connectionTime, latency, bandwidth);
    }

    @Override
    public synchronized void setReceiveBufferSize(int size) throws SocketException {
        delegate.setReceiveBufferSize(size);
    }

    @Override
    public void setReuseAddress(boolean reuse) throws SocketException {
        delegate.setReuseAddress(reuse);
    }

    @Override
    public synchronized void setSendBufferSize(int size) throws SocketException {
        delegate.setSendBufferSize(size);
    }

    @Override
    public void setSoLinger(boolean on, int timeout) throws SocketException {
        delegate.setSoLinger(on, timeout);
    }

    @Override
    public synchronized void setSoTimeout(int timeout) throws SocketException {
        delegate.setSoTimeout(timeout);
    }

    @Override
    public void setTcpNoDelay(boolean on) throws SocketException {
        delegate.setTcpNoDelay(on);
    }

    @Override
    public void setTrafficClass(int value) throws SocketException {
        delegate.setTrafficClass(value);
    }

    @Override
    public void shutdownInput() throws IOException {
        delegate.shutdownInput();
    }

    @Override
    public void shutdownOutput() throws IOException {
        delegate.shutdownOutput();
    }

    @Override
    public String toString() {
        return delegate.toString();
    }

    @Override
    public boolean equals(Object o) {
        return delegate.equals(o);
    }
}
}

Bağlanırken bu sınıfı şu şekilde kullanın:

SSLContext sslcontext = SSLContext.getInstance("TLSv1");
sslcontext.init(null, null, null);
SSLSocketFactory NoSSLv3Factory = new NoSSLv3SocketFactory(sslcontext.getSocketFactory());

HttpsURLConnection.setDefaultSSLSocketFactory(NoSSLv3Factory);
l_connection = (HttpsURLConnection) l_url.openConnection();
l_connection.connect();

GÜNCELLEME :

Şimdi, doğru çözüm Google Play Hizmetlerini kullanarak daha yeni bir güvenlik sağlayıcısı kurmak olacaktır :

    ProviderInstaller.installIfNeeded(getApplicationContext());

Bu, uygulamanızın SSLEngine'de TLSv1.2 desteği içeren daha yeni bir OpenSSL ve Java Güvenlik Sağlayıcısı sürümüne etkili bir şekilde erişmesini sağlar. Yeni sağlayıcı yüklendikten sonra, SSLv3, TLSv1, TLSv1.1 ve TLSv1.2'yi her zamanki gibi destekleyen bir SSLEngine oluşturabilirsiniz:

    SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
    sslContext.init(null, null, null);
    SSLEngine engine = sslContext.createSSLEngine();

Veya kullanarak etkinleştirilen protokolleri kısıtlayabilirsiniz engine.setEnabledProtocols.

Aşağıdaki bağımlılığı eklemeyi unutmayın ( en son sürümü buradan kontrol edin ):

implementation 'com.google.android.gms:play-services-auth:17.0.0'

Daha fazla bilgi için bu bağlantıya bakın .


25
Bir Lollipop cihazında bu hatayı alıyorsam ne olur?
IgorGanapolsky

2
Bunu 5.0.1'de alıyorum
Skynet

Bu yaklaşım, SSLCertificateSocketFactory.setHostname (Socket, String) yöntemini sağlamayarak SNI'yi etkin bir şekilde devre dışı bıraktığından, sanal bir ana bilgisayara bağlanırken başarısız görünüyor. Openssl.exe ve tarayıcının sorun olmadan bağlandığı 403'leri alıyorum. Eksik SNI olduğu ortaya çıktı.
Jaroslav Záruba

2
bunu voleybolla nasıl kullanabilirim?
uniruddh

1
Android API 19'da bu hatayı alıyorum javax.net.ssl.SSLProtocolException: Okuma hatası: ssl = 0xb83d7120: SSL kitaplığında hata, genellikle bir protokol hatası
Rukmal Dias

118

Senaryo

Android 5.0'dan önceki Android sürümlerini çalıştıran cihazlarda SSLHandshake istisnaları alıyordum. Kullanım durumumda, istemci sertifikama güvenmek için bir TrustManager oluşturmak istedim.

Ben hayata NoSSLv3SocketFactory ve NoSSLv3Factory desteklenen protokoller müvekkilimin listeden SSLv3 kaldırmak için ama işe Bu çözümlerden hiçbiri alabilir.

Öğrendiğim bazı şeyler:

  • Android 5.0'dan daha eski cihazlarda TLSv1.1 ve TLSv1.2 protokolleri varsayılan olarak etkin değildir.
  • SSLv3 protokolü, Android 5.0'dan daha eski cihazlarda varsayılan olarak devre dışı bırakılmamıştır.
  • SSLv3 güvenli bir protokol değildir ve bu nedenle, bir bağlantı yapılmadan önce müşterimizin desteklenen protokoller listesinden kaldırılması arzu edilir.

Benim için ne işe yaradı

ProviderUygulamanızı başlatırken Android güvenliğinin güncellenmesine izin verin .

5.0+ öncesi varsayılan Sağlayıcı, SSLv3'ü devre dışı bırakmaz. Google Play hizmetlerine erişiminiz olması koşuluyla, Android'in güvenlik Sağlayıcısına uygulamanızdan yama yapmak nispeten kolaydır.

private void updateAndroidSecurityProvider(Activity callingActivity) {
    try {
        ProviderInstaller.installIfNeeded(this);
    } catch (GooglePlayServicesRepairableException e) {
        // Thrown when Google Play Services is not installed, up-to-date, or enabled
        // Show dialog to allow users to install, update, or otherwise enable Google Play services.
        GooglePlayServicesUtil.getErrorDialog(e.getConnectionStatusCode(), callingActivity, 0);
    } catch (GooglePlayServicesNotAvailableException e) {
        Log.e("SecurityException", "Google Play Services not available.");
    }
}

Şimdi OkHttpClient veya HttpURLConnection'ınızı oluşturursanız, TLSv1.1 ve TLSv1.2 protokol olarak mevcut olmalı ve SSLv3 kaldırılmalıdır. İstemci / bağlantı (veya daha spesifik olarak SSLContext) aramadan önce başlatılmışsa ProviderInstaller.installIfNeeded(...), yeniden oluşturulması gerekecektir.

Aşağıdaki bağımlılığı eklemeyi unutmayın ( en son sürüm burada bulunur ):

compile 'com.google.android.gms:play-services-auth:16.0.1'

Kaynaklar:

Bir yana

İstemcimin hangi şifre algoritmalarını kullanması gerektiğini açıkça ayarlamama gerek yoktu, ancak yazarken en güvenli kabul edilenleri öneren bir SO gönderisi buldum: SSL Soketini etkinleştirmek için hangi Şifre Takımları?


1
Google Play Hizmetlerini çalıştıran cihazların sayısı için yayınlanan herhangi bir istatistik bilmiyorum. Bulabildiğim en son rakam, Sundar Pichai'nin IO 2014 konuşmasında Android cihazların% 93'ünün Play Services'in en son sürümüne sahip olduğunu söyledi. Manuel bir yöntemle ilgili olarak, tüm manuel yöntemler benim için işe yaramadığında bu çözüme ulaştım. Ağ güvenliği, kullanıcılarınız için hayati önem taşımıyorsa, kullanıcı Play Hizmetlerini yüklemeyi reddederse her zaman HTTP'ye geri dönebilirsiniz. Kendi uygulamamız için uyumluluk ve güvenlik arasındaki dengeyi düşündük. Play Hizmetleri güncellemesini zorunlu kılıyoruz.
Maurice Gavin

3
Çin'deki Google Play Hizmetleri desteği çok sınırlıdır. Hedef kitlenize bağlı olarak bilmek iyi olabilir. Ancak, Google Play aracılığıyla dağıtırsanız, bu kitle zaten kaybediyor.
jayeffkay

3
Çözümün çalışması için lütfen bu bağımlılığı ekleyin. derleyin 'com.google.android.gms: play-services-auth: 10.2.0',
Pradeep Chakravarti Gudipati

3
ProviderInstaller.installIfNeeded (this) ekleniyor; Uygulama'nın onCreate () parçası benim için çalıştı! Teşekkürler :-)
Kelevandos

1
Kesinlikle buradaki en faydalı cevap. Böyle paha biçilmez bir yardım için teşekkürler.
Burak Karakuş

50

Ayrıca, varsayılan olarak etkinleştirilmemiş Android 4.0 cihazlar için TLS v1.2'yi zorlayabileceğinizi de bilmelisiniz:

Bu kodu Uygulama dosyanızın onCreate () bölümüne koyun :

try {
        ProviderInstaller.installIfNeeded(getApplicationContext());
        SSLContext sslContext;
        sslContext = SSLContext.getInstance("TLSv1.2");
        sslContext.init(null, null, null);
        sslContext.createSSLEngine();
    } catch (GooglePlayServicesRepairableException | GooglePlayServicesNotAvailableException
            | NoSuchAlgorithmException | KeyManagementException e) {
        e.printStackTrace();
    }

7
Benim için rxJava OkHttpClient.Builder ile çalıştı, çok teşekkürler.
Gweltaz Niquel

2
Android 7.0'da çalışır.
CoolMind

1
teşekkürler @mayur gangurde, bu, oyun hizmetleri auth gradle, uygulama 'com.google.android.gms: play-services-auth: 16.0.1'
Basant

Mükemmel çalıştı. Bana saatlerce test edip denemekten kurtardığın için çok teşekkür ederim.
Ninad Desai

Bu çok uygundur. Çok teşekkürler!
Caspar Geerlings

15

Daha önce, bu sorunu özel SSLFactoryuygulama ile de çözmüştüm , ancak OkHttp belgelerine göre çözüm çok daha kolay.

TLS4.2+ cihaz için gerekli şifrelere sahip son çözümüm şöyle görünüyor:

public UsersApi provideUsersApi() {

    private ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS)
        .supportsTlsExtensions(true)
        .tlsVersions(TlsVersion.TLS_1_2, TlsVersion.TLS_1_1, TlsVersion.TLS_1_0)
        .cipherSuites(
                CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
                CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
                CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
                CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
                CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
                CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
                CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
                CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA)
        .build();

    OkHttpClient client = new OkHttpClient.Builder()
            .connectionSpecs(Collections.singletonList(spec))
            .build();

    return new Retrofit.Builder()
            .baseUrl(USERS_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(client)
            .build()
            .create(UsersApi.class);
}

Desteklenen protokol setinin sunucunuzda yapılandırılmaya bağlı olduğunu unutmayın.


Çözümünüz API 14'ü destekliyor mu?
CoolMind

Kesin olarak söyleyemem, bunu yalnızca 16+ API cihazında test etti, iyi çalışıyor.
Fragment

1
Fragment, sevimli bir takma ad :) Kabul ediyorum, API 14 emülatörünü bile başlatamadım, ancak çözümünüz Android 7.0'da (sorun vardı) ve API 19'da çalışıyor.
CoolMind

1
Teşekkürler, test ettim, işe yaradı. Bugün yine bir API 19 öykünücüsü başlattı ve bir çözüm stackoverflow.com/a/51285550/2914140 eklemek zorunda kaldı .
CoolMind

13

Çözümü burada bu bağlantıda buldum .

Android uygulama sınıfınıza aşağıdaki kodu yerleştirmeniz yeterlidir. Ve bu yeterli. Retrofit ayarlarınızda herhangi bir değişiklik yapmanız gerekmez. Günümü kurtardı.

public class MyApplication extends Application {
@Override
public void onCreate() {
    super.onCreate();
    try {
      // Google Play will install latest OpenSSL 
      ProviderInstaller.installIfNeeded(getApplicationContext());
      SSLContext sslContext;
      sslContext = SSLContext.getInstance("TLSv1.2");
      sslContext.init(null, null, null);
      sslContext.createSSLEngine();
    } catch (GooglePlayServicesRepairableException | GooglePlayServicesNotAvailableException
        | NoSuchAlgorithmException | KeyManagementException e) {
        e.printStackTrace();
        }
    }
}

Umarım bu yardımcı olur. Teşekkür ederim.



4

Bu benim için çözdü:

SSLSocket için Android dokümantasyonu, TLS 1.1 ve TLS 1.2'nin android başlangıç ​​API seviyesi 16+ (Android 4.1, Jelly Bean) içinde desteklendiğini söylüyor. Ancak varsayılan olarak devre dışıdır ancak API seviyesi 20+ (saat için Android 4.4, Telefon için Kitkat Watch ve Android 5.0, Lollipop) ile başlayarak etkinleştirilirler. Ancak, örneğin 4.1 çalıştıran telefonlar için nasıl etkinleştirileceğine dair herhangi bir belge bulmak çok zordur. TLS 1.1 ve 1.2'yi etkinleştirmek için, tüm çağrıları varsayılan bir SSLSocketFactory uygulamasına vekil olarak sunacak özel bir SSLSocketFactory oluşturmanız gerekir. Buna ek olarak, TLS 1.1 ve TLS 1.2'yi etkinleştirmek için döndürülen SSLSocket üzerindeki tüm createSocket yöntemlerini ve callsetEnabledProtocols'u geçersiz kılmak zorundayız. Örnek bir uygulama için aşağıdaki bağlantıyı takip etmeniz yeterlidir.

android 4.1. tls1.1 ve tls 1.2'yi etkinleştir


2

Bu hata raporu sorununu da bende var. Kodum aşağıda.

public static void getShop() throws Exception {
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                OkHttpClient client = new OkHttpClient();
                Request request = new Request.Builder()
                        .url("https://10.0.2.2:8010/getShopInfo/aaa")
                        .build();
                Response response = client.newCall(request).execute();
                Log.d("response", response.body().string());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }).start();
}

Arka ucum olarak Springboot'um var ve bilgi almak için Android OKHttp kullanıyorum. Yaptığım kritik hata , Android kodunda bir .url ( "https : //10.0.2.2: 8010 / getShopInfo / aaa") kullanmamdı . Ancak arka ucumun https isteğine izin verilmiyor. İ kullandıktan sonra .url ( " http : //10.0.2.2: 8010 / getShopInfo / aaa") , sonra benim kod iyi gitti. Bu yüzden, hatamın emülatörün versiyonu olmadığını, istek protokolü ile ilgili olduğunu söylemek istiyorum. Söylediklerimi yaptıktan sonra başka bir sorunla karşılaşıyorum ama bu başka bir sorun ve yeni sorunun çözüm yöntemini ekliyorum .
İyi Şanslar!


1

Yalnızca genymotion (<4.4) üzerinde proxy kullandığımda tekrarlanabilirdi.

Ayarlar-> Kablosuz ve Ağlar-> WiFi -> (Uzun Basma WiredSSID) -> Ağı Değiştir'den proxy ayarlarınızı kontrol edin

Gelişmiş seçenekleri göster'i seçin: Proxy ayarlarını HİÇBİRİ olarak ayarlayın.


1

Bu hatayı aldığımda, bunun nedeni sunucu tarafından desteklenen protokollerin (TLS sürümleri) ve / veya şifre paketlerinin cihazda etkinleştirilmemesidir (ve muhtemelen desteklenmiyor). API 16-19 için TLSv1.1 ve TLSv1.2 desteklenir ancak varsayılan olarak etkinleştirilmez. Bunları bu sürümler için etkinleştirdikten sonra yine de hatayı alıyorum çünkü bu sürümler AWS CloudFront örneğimizdeki hiçbir şifreyi desteklemiyor.

Android'e şifre eklemek mümkün olmadığından, CloudFront sürümümüzü TLSv1.2_2018'den TLSv1.1_2016'ya (hala TLSv1.2'yi destekliyor; sadece gerektirmiyor), dört şifrenin desteklediği önceki Android sürümleri, ikisi hala güçlü olarak kabul ediliyor.

Bu noktada, hata ortadan kalktı ve aramalar (TLSv1.2 ile) gerçekleşti çünkü cihaz ve sunucunun paylaştığı en az bir protokol ve en az bir şifre vardı.

Hangi protokollerin ve şifrelerin hangi Android sürümleri tarafından desteklendiğini ve etkinleştirildiğini görmek için bu sayfadaki tablolara bakın .

Şimdi Android, hata mesajının "sslv3 uyarı anlaşması hatası" bölümünde belirtildiği gibi SSLv3'ü kullanmaya gerçekten çalışıyor muydu? Şüpheliyim; Bunun SSL kitaplığındaki temizlenmemiş eski bir örümcek ağı olduğundan şüpheleniyorum ama kesin olarak söyleyemem.

TLSv1.2'yi (ve TLSv1.1'i) etkinleştirmek için, SSLSocketFactorybaşka yerlerde görülenlerden (gibi NoSSLv3SocketFactory) çok daha basitini kullanabildim . Basitçe, etkinleştirilen protokollerin desteklenen tüm protokolleri içerdiğinden ve etkinleştirilen şifrelerin desteklenen tüm şifreleri içerdiğinden emin olur (ikincisi benim için gerekli değildi, ancak diğerleri için olabilir) - aşağıya bakın configure(). Yalnızca en son protokolleri etkinleştirmeyi tercih ederseniz, aşağıdaki socket.supportedProtocolsgibi bir şeyle değiştirebilirsiniz arrayOf("TLSv1.1", "TLSv1.2")(aynı şekilde şifreler için):

class TLSSocketFactory : SSLSocketFactory() {

    private val socketFactory: SSLSocketFactory

    init {
        val sslContext = SSLContext.getInstance("TLS")
        sslContext.init(null, null, null)
        socketFactory = sslContext.socketFactory
    }

    override fun getDefaultCipherSuites(): Array<String> {
        return socketFactory.defaultCipherSuites
    }

    override fun getSupportedCipherSuites(): Array<String> {
        return socketFactory.supportedCipherSuites
    }

    override fun createSocket(s: Socket, host: String, port: Int, autoClose: Boolean): Socket {
        return configure(socketFactory.createSocket(s, host, port, autoClose) as SSLSocket)
    }

    override fun createSocket(host: String, port: Int): Socket {
        return configure(socketFactory.createSocket(host, port) as SSLSocket)
    }

    override fun createSocket(host: InetAddress, port: Int): Socket {
        return configure(socketFactory.createSocket(host, port) as SSLSocket)
    }

    override fun createSocket(host: String, port: Int, localHost: InetAddress, localPort: Int): Socket {
        return configure(socketFactory.createSocket(host, port, localHost, localPort) as SSLSocket)
    }

    override fun createSocket(address: InetAddress, port: Int, localAddress: InetAddress, localPort: Int): Socket {
        return configure(socketFactory.createSocket(address, port, localAddress, localPort) as SSLSocket)
    }

    private fun configure(socket: SSLSocket): SSLSocket {
        socket.enabledProtocols = socket.supportedProtocols
        socket.enabledCipherSuites = socket.supportedCipherSuites
        return socket
    }
}

Nasıl kullanıyorsun?
CoolMind

0

Sorunu şu şekilde çözdüm: NoSSLv3SocketFactory.java

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

public class NoSSLv3SocketFactory extends SSLSocketFactory {
    private final SSLSocketFactory delegate;

    public NoSSLv3SocketFactory() {
        this.delegate = HttpsURLConnection.getDefaultSSLSocketFactory();
    }

    public NoSSLv3SocketFactory(SSLSocketFactory delegate) {
        this.delegate = delegate;
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return delegate.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return delegate.getSupportedCipherSuites();
    }

    private Socket makeSocketSafe(Socket socket) {
        if (socket instanceof SSLSocket) {
            socket = new NoSSLv3SSLSocket((SSLSocket) socket);
        }
        return socket;
    }

    @Override
    public Socket createSocket(Socket s, String host, int port,
            boolean autoClose) throws IOException {
        return makeSocketSafe(delegate.createSocket(s, host, port, autoClose));
    }

    @Override
    public Socket createSocket(String host, int port) throws IOException {
        return makeSocketSafe(delegate.createSocket(host, port));
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost,
            int localPort) throws IOException {
        return makeSocketSafe(delegate.createSocket(host, port, localHost,
                localPort));
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return makeSocketSafe(delegate.createSocket(host, port));
    }

    @Override
    public Socket createSocket(InetAddress address, int port,
            InetAddress localAddress, int localPort) throws IOException {
        return makeSocketSafe(delegate.createSocket(address, port,
                localAddress, localPort));
    }

    private class NoSSLv3SSLSocket extends DelegateSSLSocket {

        private NoSSLv3SSLSocket(SSLSocket delegate) {
            super(delegate);

        }

        @Override
        public void setEnabledProtocols(String[] protocols) {
            if (protocols != null && protocols.length == 1
                    && "SSLv3".equals(protocols[0])) {

                List<String> enabledProtocols = new ArrayList<String>(
                        Arrays.asList(delegate.getEnabledProtocols()));
                if (enabledProtocols.size() > 1) {
                    enabledProtocols.remove("SSLv3");
                    System.out.println("Removed SSLv3 from enabled protocols");
                } else {
                    System.out.println("SSL stuck with protocol available for "
                            + String.valueOf(enabledProtocols));
                }
                protocols = enabledProtocols
                        .toArray(new String[enabledProtocols.size()]);
            }

//          super.setEnabledProtocols(protocols);
            super.setEnabledProtocols(new String[]{"TLSv1.2"});
        }
    }

    public class DelegateSSLSocket extends SSLSocket {

        protected final SSLSocket delegate;

        DelegateSSLSocket(SSLSocket delegate) {
            this.delegate = delegate;
        }

        @Override
        public String[] getSupportedCipherSuites() {
            return delegate.getSupportedCipherSuites();
        }

        @Override
        public String[] getEnabledCipherSuites() {
            return delegate.getEnabledCipherSuites();
        }

        @Override
        public void setEnabledCipherSuites(String[] suites) {
            delegate.setEnabledCipherSuites(suites);
        }

        @Override
        public String[] getSupportedProtocols() {
            return delegate.getSupportedProtocols();
        }

        @Override
        public String[] getEnabledProtocols() {
            return delegate.getEnabledProtocols();
        }

        @Override
        public void setEnabledProtocols(String[] protocols) {
            delegate.setEnabledProtocols(protocols);
        }

        @Override
        public SSLSession getSession() {
            return delegate.getSession();
        }

        @Override
        public void addHandshakeCompletedListener(
                HandshakeCompletedListener listener) {
            delegate.addHandshakeCompletedListener(listener);
        }

        @Override
        public void removeHandshakeCompletedListener(
                HandshakeCompletedListener listener) {
            delegate.removeHandshakeCompletedListener(listener);
        }

        @Override
        public void startHandshake() throws IOException {
            delegate.startHandshake();
        }

        @Override
        public void setUseClientMode(boolean mode) {
            delegate.setUseClientMode(mode);
        }

        @Override
        public boolean getUseClientMode() {
            return delegate.getUseClientMode();
        }

        @Override
        public void setNeedClientAuth(boolean need) {
            delegate.setNeedClientAuth(need);
        }

        @Override
        public void setWantClientAuth(boolean want) {
            delegate.setWantClientAuth(want);
        }

        @Override
        public boolean getNeedClientAuth() {
            return delegate.getNeedClientAuth();
        }

        @Override
        public boolean getWantClientAuth() {
            return delegate.getWantClientAuth();
        }

        @Override
        public void setEnableSessionCreation(boolean flag) {
            delegate.setEnableSessionCreation(flag);
        }

        @Override
        public boolean getEnableSessionCreation() {
            return delegate.getEnableSessionCreation();
        }

        @Override
        public void bind(SocketAddress localAddr) throws IOException {
            delegate.bind(localAddr);
        }

        @Override
        public synchronized void close() throws IOException {
            delegate.close();
        }

        @Override
        public void connect(SocketAddress remoteAddr) throws IOException {
            delegate.connect(remoteAddr);
        }

        @Override
        public void connect(SocketAddress remoteAddr, int timeout)
                throws IOException {
            delegate.connect(remoteAddr, timeout);
        }

        @Override
        public SocketChannel getChannel() {
            return delegate.getChannel();
        }

        @Override
        public InetAddress getInetAddress() {
            return delegate.getInetAddress();
        }

        @Override
        public InputStream getInputStream() throws IOException {
            return delegate.getInputStream();
        }

        @Override
        public boolean getKeepAlive() throws SocketException {
            return delegate.getKeepAlive();
        }

        @Override
        public InetAddress getLocalAddress() {
            return delegate.getLocalAddress();
        }

        @Override
        public int getLocalPort() {
            return delegate.getLocalPort();
        }

        @Override
        public SocketAddress getLocalSocketAddress() {
            return delegate.getLocalSocketAddress();
        }

        @Override
        public boolean getOOBInline() throws SocketException {
            return delegate.getOOBInline();
        }

        @Override
        public OutputStream getOutputStream() throws IOException {
            return delegate.getOutputStream();
        }

        @Override
        public int getPort() {
            return delegate.getPort();
        }

        @Override
        public synchronized int getReceiveBufferSize() throws SocketException {
            return delegate.getReceiveBufferSize();
        }

        @Override
        public SocketAddress getRemoteSocketAddress() {
            return delegate.getRemoteSocketAddress();
        }

        @Override
        public boolean getReuseAddress() throws SocketException {
            return delegate.getReuseAddress();
        }

        @Override
        public synchronized int getSendBufferSize() throws SocketException {
            return delegate.getSendBufferSize();
        }

        @Override
        public int getSoLinger() throws SocketException {
            return delegate.getSoLinger();
        }

        @Override
        public synchronized int getSoTimeout() throws SocketException {
            return delegate.getSoTimeout();
        }

        @Override
        public boolean getTcpNoDelay() throws SocketException {
            return delegate.getTcpNoDelay();
        }

        @Override
        public int getTrafficClass() throws SocketException {
            return delegate.getTrafficClass();
        }

        @Override
        public boolean isBound() {
            return delegate.isBound();
        }

        @Override
        public boolean isClosed() {
            return delegate.isClosed();
        }

        @Override
        public boolean isConnected() {
            return delegate.isConnected();
        }

        @Override
        public boolean isInputShutdown() {
            return delegate.isInputShutdown();
        }

        @Override
        public boolean isOutputShutdown() {
            return delegate.isOutputShutdown();
        }

        @Override
        public void sendUrgentData(int value) throws IOException {
            delegate.sendUrgentData(value);
        }

        @Override
        public void setKeepAlive(boolean keepAlive) throws SocketException {
            delegate.setKeepAlive(keepAlive);
        }

        @Override
        public void setOOBInline(boolean oobinline) throws SocketException {
            delegate.setOOBInline(oobinline);
        }

        @Override
        public void setPerformancePreferences(int connectionTime, int latency,
                int bandwidth) {
            delegate.setPerformancePreferences(connectionTime, latency,
                    bandwidth);
        }

        @Override
        public synchronized void setReceiveBufferSize(int size)
                throws SocketException {
            delegate.setReceiveBufferSize(size);
        }

        @Override
        public void setReuseAddress(boolean reuse) throws SocketException {
            delegate.setReuseAddress(reuse);
        }

        @Override
        public synchronized void setSendBufferSize(int size)
                throws SocketException {
            delegate.setSendBufferSize(size);
        }

        @Override
        public void setSoLinger(boolean on, int timeout) throws SocketException {
            delegate.setSoLinger(on, timeout);
        }

        @Override
        public synchronized void setSoTimeout(int timeout)
                throws SocketException {
            delegate.setSoTimeout(timeout);
        }

        @Override
        public void setTcpNoDelay(boolean on) throws SocketException {
            delegate.setTcpNoDelay(on);
        }

        @Override
        public void setTrafficClass(int value) throws SocketException {
            delegate.setTrafficClass(value);
        }

        @Override
        public void shutdownInput() throws IOException {
            delegate.shutdownInput();
        }

        @Override
        public void shutdownOutput() throws IOException {
            delegate.shutdownOutput();
        }

        @Override
        public String toString() {
            return delegate.toString();
        }

        @Override
        public boolean equals(Object o) {
            return delegate.equals(o);
        }
    }
}

Ana sınıf :

URL url = new URL("https://www.example.com/test.png");
URLConnection l_connection = null;
SSLContext sslcontext = SSLContext.getInstance("TLSv1.2");
sslcontext.init(null, null, null);
SSLSocketFactory NoSSLv3Factory = new NoSSLv3SocketFactory(sslcontext.getSocketFactory());

0

Cevabım yukarıdaki cevaplara yakın ancak hiçbir şeyi değiştirmeden sınıfı aynen yazmanız gerekiyor.

public class TLSSocketFactory extends SSLSocketFactory {

private SSLSocketFactory delegate;

public TLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException {
    SSLContext context = SSLContext.getInstance("TLS");
    context.init(null, null, null);
    delegate = context.getSocketFactory();
}

@Override
public String[] getDefaultCipherSuites() {
    return delegate.getDefaultCipherSuites();
}

@Override
public String[] getSupportedCipherSuites() {
    return delegate.getSupportedCipherSuites();
}

@Override
public Socket createSocket() throws IOException {
    return enableTLSOnSocket(delegate.createSocket());
}

@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
    return enableTLSOnSocket(delegate.createSocket(s, host, port, autoClose));
}

@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
    return enableTLSOnSocket(delegate.createSocket(host, port));
}

@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
    return enableTLSOnSocket(delegate.createSocket(host, port, localHost, localPort));
}

@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
    return enableTLSOnSocket(delegate.createSocket(host, port));
}

@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
    return enableTLSOnSocket(delegate.createSocket(address, port, localAddress, localPort));
}

private Socket enableTLSOnSocket(Socket socket) {
    if(socket != null && (socket instanceof SSLSocket)) {
        ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
    }
    return socket;
}

}

ve HttpsURLConnection ile kullanmak için

HttpsURLConnection  conn = (HttpsURLConnection) url.openConnection();

int sdk = android.os.Build.VERSION.SDK_INT;
            if (sdk < Build.VERSION_CODES.LOLLIPOP) {
                if (url.toString().startsWith("https")) {
                    try {
                        TLSSocketFactory sc = new TLSSocketFactory();
                        conn.setSSLSocketFactory(sc);
                    } catch (Exception e) {
                        String sss = e.toString();
                    }
                }
            }
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.