【问题标题】:Javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: Failure in SSL library, usually a protocol errorJavax.net.ssl.SSLHandshakeException:javax.net.ssl.SSLProtocolException:SSL握手中止:SSL库失败,通常是协议错误
【发布时间】:2015-07-07 03:48:34
【问题描述】:

我正在尝试在 android 中运行以下代码

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

l_connection.connect() 上,它给出了这个 SSLhandshakeException。有时它有效,但大多数时候它给出了例外。它只发生在 Android 4.0 模拟器上。我在 Android 4.4 和 5.0 上测试过,效果很好。这可能是什么原因?请帮忙

堆栈跟踪

    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

【问题讨论】:

  • 您是否在真实设备上检查过您的应用?
  • 它给出了什么异常?堆栈跟踪?
  • @PareshMayani 是的,即使在具有 Android 4.0 的真实设备上,它也会显示异常。
  • @EJP 我已经更新了问题,添加了stacktrace。
  • 这是 only 标记 jellybean 的问题。你的意思是android-4.2-jelly-bean

标签: android ssl sslhandshakeexception android-4.0.3-ice-cream-sandwich


【解决方案1】:

我通过使用wireshark分析数据包找到了解决方案。我发现,在建立安全连接时,android 从 TLSv1 回退到 SSLv3 。这是 android 版本

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

在连接时像这样使用这个类:

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

更新:

现在,正确的解决方案是使用 Google Play Services 安装更新的安全提供程序:

    ProviderInstaller.installIfNeeded(getApplicationContext());

这有效地使您的应用可以访问更新版本的 OpenSSL 和 Java 安全提供程序,其中包括对 SSLEngine 中的 TLSv1.2 的支持。安装新的提供程序后,您可以按照通常的方式创建支持 SSLv3、TLSv1、TLSv1.1 和 TLSv1.2 的 SSLEngine:

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

或者您可以使用engine.setEnabledProtocols 限制启用的协议。

不要忘记添加以下依赖项(check the latest version here):

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

欲了解更多信息,请查看此link

【讨论】:

  • 如果我在 Lollipop 设备上收到此错误怎么办?
  • 我在 5.0.1 上得到这个
  • 这种方法在连接到虚拟主机时似乎失败了,因为它通过不提供 SSLCertificateSocketFactory.setHostname(Socket, String) 方法有效地禁用了 SNI。我得到了 403s,其中 openssl.exe 和浏览器连接没有问题。原来是丢失的 SNI。
  • 如何将它与 volley 一起使用?
  • 我在 Android API 19 javax.net.ssl.SSLProtocolException 中收到此错误:读取错误:ssl=0xb83d7120:SSL 库失败,通常是协议错误
【解决方案2】:

只有当我在 genymotion(

检查您的代理设置 设置->无线和网络->WiFi->(长按WiredSSID)->修改网络

选择显示高级选项: 将代理设置设置为 NONE。

【讨论】:

    【解决方案3】:

    场景

    我在运行早于 Android 5.0 的 Android 版本的设备上遇到 SSLHandshake 异常。在我的用例中,我还想创建一个 TrustManager 来信任我的客户端证书。

    我实现了 NoSSLv3SocketFactoryNoSSLv3Factory 以从我的客户支持的协议列表中删除 SSLv3,但我无法让这两种解决方案都能正常工作。

    我学到的一些东西:

    • 在低于 Android 5.0 的设备上,TLSv1.1 和 TLSv1.2 协议默认不启用。
    • 默认情况下,在 Android 5.0 之前的设备上未禁用 SSLv3 协议。
    • SSLv3 is not a secure 协议,因此最好在建立连接之前将其从客户支持的协议列表中删除。

    什么对我有用

    在启动您的应用时允许 Android 的安全 Provider 更新。

    5.0+ 之前的默认 Provider 不会禁用 SSLv3。如果您可以访问 Google Play 服务,那么从您的应用中修补 Android 的安全提供程序相对简单。

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

    如果您现在创建 OkHttpClient 或 HttpURLConnection,TLSv1.1 和 TLSv1.2 应该可以作为协议使用,并且应该删除 SSLv3。如果客户端/连接(或更具体地说是 SSLContext)在调用 ProviderInstaller.installIfNeeded(...) 之前已初始化,则需要重新创建。

    不要忘记添加以下依赖项(latest version found here):

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

    来源:

    一边

    我不需要明确设置我的客户应该使用哪些密码算法,但我发现一个 SO 帖子推荐了在撰写本文时被认为最安全的算法:Which Cipher Suites to enable for SSL Socket?

    【讨论】:

    • 这种方法确实有效。可悲的是,这迫使我的应用程序使用与某些设备不兼容的 Google Play 服务。然而,这些只是少数。不是吗?有没有办法手动更新提供者?
    • 我不知道有关运行 Google Play 服务的设备数量的任何已发布统计数据。我能找到的最新数据是 Sundar Pichai 在 2014 年的 IO 演讲中,他说 93% 的 Android 设备都有最新版本的 Play Services。关于手动方法,当所有手动方法都对我不起作用时,我得出了这个解决方案。如果网络安全对您的用户来说不是很重要,如果用户拒绝安装 Play 服务,您总是可以回退到 HTTP。对于我们自己的应用程序,我们考虑了兼容性和安全性之间的权衡。我们强制更新 Play 服务。
    • Google Play Services 在中国的支持非常有限。根据您的目标受众,可能会很高兴。但是,如果您通过 Google Play 分发,那么这些受众已经错过了。
    • 请添加此依赖项以使解决方案正常工作。编译 'com.google.android.gms:play-services-auth:10.2.0',
    • 添加 ProviderInstaller.installIfNeeded(this);应用程序的 onCreate() 部分为我工作!谢谢:-)
    【解决方案4】:

    我通过这个解决了问题: 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);
            }
        }
    }
    

    主类:

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

    【讨论】:

      【解决方案5】:

      这为我解决了:

      SSLSocket 的 Android 文档说 TLS 1.1 和 TLS 1.2 在 android 起始 API 级别 16+(Android 4.1,Jelly Bean)中受支持。但默认情况下它是禁用的,但从 API 级别 20+(Android 4.4 for watch、Kitkat Watch 和 Android 5.0 for phone、Lollipop)开始它们是启用的。但是很难找到任何关于如何为运行 4.1 的手机启用它的文档。 要启用 TLS 1.1 和 1.2,您需要创建一个自定义 SSLSocketFactory,它将所有调用代理到默认 SSLSocketFactory 实现。除此之外,我们还必须覆盖所有 createSocket 方法并在返回的 SSLSocket 上调用 setEnabledProtocols 以启用 TLS 1.1 和 TLS 1.2。如需示例实现,请点击以下链接。

      android 4.1. enable tls1.1 and tls 1.2

      【讨论】:

        【解决方案6】:

        当我收到此错误时,是因为设备未启用(甚至可能不支持)服务器支持的协议(TLS 版本)和/或密码套件。对于 API 16-19,TLSv1.1 和 TLSv1.2 受支持,但默认不启用。为这些版本启用它们后,我仍然收到错误消息,因为这些版本不支持我们的 AWS CloudFront 实例上的任何密码。

        由于无法将密码添加到 Android,我们不得不将 CloudFront 版本从 TLSv1.2_2018 切换到 TLSv1.1_2016(它仍然支持 TLSv1.2;它只是不需要它),它有四个早期 Android 版本支持的密码,其中两个仍然被认为是强大的。

        此时,错误消失并且调用通过(使用 TLSv1.2),因为设备和服务器共享了至少一种协议和至少一种密码。

        请参阅the tables on this page,了解哪些 Android 版本支持和启用哪些协议和密码。

        现在,Android 是否真的按照错误消息的“sslv3 警报握手失败”部分所暗示的那样尝试使用 SSLv3?我对此表示怀疑;我怀疑这是 SSL 库中尚未清理的旧蜘蛛网,但我不能肯定。

        为了启用 TLSv1.2(和 TLSv1.1),我可以使用比在其他地方看到的更简单的SSLSocketFactory(例如NoSSLv3SocketFactory)。它只是确保启用的协议包括所有受支持的协议,并且启用的密码包括所有受支持的密码(后者对我来说不是必需的,但对其他人来说可能是必需的) - 请参阅底部的 configure()。如果您只想启用最新的协议,可以将socket.supportedProtocols 替换为arrayOf("TLSv1.1", "TLSv1.2") 之类的东西(密码也一样):

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

        【讨论】:

        • 你是怎么用的?
        【解决方案7】:

        以前,我也用自定义SSLFactory 实现解决了这个问题,但是根据OkHttp docs,解决方案要容易得多。

        4.2+ 设备所需的TLS 密码的最终解决方案如下所示:

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

        请注意,支持的协议集取决于您的服务器上的配置。

        【讨论】:

        • 您的解决方案是否支持 API 14?
        • 不能肯定,仅在 16+ API 设备上测试过,工作正常。
        • Fragment,一个可爱的昵称 :) 我同意,甚至无法启动 API 14 模拟器,但您的解决方案适用于 Android 7.0(有问题)和 API 19。
        • 谢谢,我测试过,它有效。今天又推出了一个API 19模拟器,不得不添加解决方案stackoverflow.com/a/51285550/2914140
        【解决方案8】:

        您还应该知道,对于默认情况下未启用的 Android 4.0 设备,您可以强制使用 TLS v1.2:

        将此代码放在应用程序文件的 onCreate() 中

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

        【讨论】:

        • 使用 rxJava OkHttpClient.Builder 为我工作,非常感谢。
        • 适用于 Android 7.0。
        • 感谢@mayur gangurde,这是为我添加播放服务身份验证 gradle 后的工作,实施 'com.google.android.gms:play-services-auth:16.0.1'
        • 完美运行。非常感谢您为我节省了数小时的测试和尝试时间。
        • 这个很方便。非常感谢!
        【解决方案9】:

        我的答案与上述答案很接近,但您需要完全编写课程而不做任何更改。

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

        }

        并将其与 HttpsURLConnection 一起使用

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

        【讨论】:

          【解决方案10】:

          我也遇到了这个错误报告问题。我的代码在下面。

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

          我将 Springboot 作为后端并使用 Android OKHttp 获取信息。我犯的严重错误是我在 Android 代码中使用了 .url("https://10.0.2.2:8010/getShopInfo/aaa")。但是我的后端不允许 https 请求。在我使用 .url("http://10.0.2.2:8010/getShopInfo/aaa") 之后,我的代码运行良好。 所以,我想说我的错误不是模拟器的版本,而是关于请求协议。我按照我说的做后遇到了另一个问题,但这是另一个问题,我附上新问题的解决方法 .
          祝你好运!伙计!

          【讨论】:

          • 您可以使用 http 而不是 https,这是一种安全连接,这会导致问题。它解决了我的问题
          【解决方案11】:

          我在this link 找到了解决方案。

          您只需将以下代码放入您的 Android 应用程序类中。这已经足够了。无需对改造设置进行任何更改。它拯救了我的一天。

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

          希望这会有所帮助。谢谢。

          【讨论】:

          猜你喜欢
          • 2021-06-14
          • 2018-09-05
          • 2018-07-10
          • 1970-01-01
          • 2018-10-03
          • 2016-06-20
          • 2017-01-09
          • 2012-01-31
          • 1970-01-01
          相关资源
          最近更新 更多