异常: SSL 握手中止: SSL 库中的失败,通常是协议错误

我尝试在 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();

On l_connection.connect(), it is giving this SSLhandshakeException. Sometimes it works, but most of the time it gives the exception. It is only happening on Android 4.0 emulator. I tested it on Android 4.4 and 5.0, it works fine. What could be the cause?

堆栈跟踪:

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
153101 次浏览

我通过使用 wireshark 分析数据包找到了解决方案。我发现,在建立安全连接时,机器人从 TLSv1退回到 SSLv3。在安卓版本 < 4.4中,这是一个 bug,可以通过从“已启用协议”列表中删除 SSLv3协议来解决。我创建了一个名为 NoSSLv3SocketFactory.java 的自定义 SocketFactory 类。用这个做一个插座工厂。

/*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 服务安装一个新的安全提供程序:

    ProviderInstaller.installIfNeeded(getApplicationContext());

这有效地使您的应用程序能够访问更新版本的 OpenSSL 和 Java Security Provider,其中包括对 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();

Or you can restrict the enabled protocols using engine.setEnabledProtocols.

不要忘记添加以下依赖项(你可在此查阅最新版本) :

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

For more info, checkout this 链接.

只有当我对基因运动使用代理(< 4.4)时,它才是可重复的。

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

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

场景

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

我实现了 NoSSLv3SocketFactoryNoSSLv3Factory,将 SSLv3从我的客户机支持的协议列表中删除,但是这两个解决方案都不能正常工作。

我学到了一些东西:

  • 在 Android 5.0以前的设备上,默认情况下不启用 TLSv1.1和 TLSv1.2协议。
  • 默认情况下,在安卓5.0以前的设备上不会禁用 SSLv3协议。
  • SSLv3不是一个安全的 协议,因此在建立连接之前,最好将它从客户机支持的协议列表中删除。

What worked for me

启动应用程序时允许 Android 的安全 Provider更新。

5.0 + 之前的默认提供程序不禁用 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(...)之前已经初始化,那么就需要重新创建它。

不要忘记添加以下依赖项(这里找到的最新版本) :

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

资料来源:

让开

我不需要明确设置我的客户应该使用哪种密码算法,但是我发现了一个 SO 帖子,推荐那些在写作时被认为是最安全的: 为 SSL 套接字启用哪个加密套件?

我用这个解决了问题: 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());

This solved it for me:

SSLSocket 的 Android 文档指出,在 Android 起始 API 级别16 + (Android 4.1,Jelly Bean)中支持 TLS 1.1和 TLS 1.2。但是默认情况下它是禁用的,但是从 API 级别20 + (手表的 Android 4.4,手机的 Kitkat Watch 和手机的 Android 5.0,棒棒糖)开始,它们是启用的。但是很难找到任何关于如何为运行4.1的手机启用它的文档。 To enable TLS 1.1 and 1.2 you need to create a custom SSLSocketFactory that is going to proxy all calls to a default SSLSocketFactory implementation. In addition to that do we have to override all createSocket methods and callsetEnabledProtocols on the returned SSLSocket to enable TLS 1.1 and TLS 1.2. For an example implementation just follow the link below.

Android 4.1. 启用 tls1.1和 tls1.2

当我得到这个错误时,是因为服务器支持的协议(TLS 版本)和/或密码套件没有在设备上启用(甚至可能没有得到设备的支持)。对于 API 16-19,支持 TLSv1.1和 TLSv1.2,但默认情况下不启用。一旦我为这些版本启用了它们,我仍然会得到错误,因为这些版本不支持我们的 AWS CloudFront 实例上的任何加密。

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

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

参考 这一页上的表格了解哪些协议和密码由哪些版本的 Android 支持并启用。

现在,Android 真的像错误消息中“ sslv3警告握手失败”部分所暗示的那样试图使用 SSLv3吗?我对此表示怀疑; 我怀疑这是 SSL 库中的一个旧蜘蛛网,还没有被清除,但我不能肯定地说。

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

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

Previously, I've also solved this problem with custom SSLFactory implementation, but according to OkHttp 文件 the solution is much easier.

我的最终解决方案是使用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);
}

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

你也应该知道,如果 Android 4.0设备默认没有启用 TLS v1.2,那么你可以强制它使用 TLS v1.2:

Put this code in onCreate() of your Application file:

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

我的答案与上面的答案很接近,但是你需要在不改变任何东西的情况下准确地写出这门课。

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

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

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 (< strong > “ https ://10.0.2.2:8010/getShopInfo/aaa”)。但是我的后端不允许 https 请求。在我使用 . url (“ < strong > http ://10.0.2.2:8010/getShopInfo/aaa”)之后,我的代码运行得很好。 So, i want to say my mistake is not the version of emulator, it about the request protocol. I meet another problem after doing what i said, but it's another problem, and i attach the resolve method of the new problem 祝你好运! 伙计!

I found the solution here in 这个链接.

您只需将下面的代码放置在您的 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();
}
}
}