【问题标题】:javax.net.ssl.SSLHandshakeException: Handshake failed on Android 5.0.0 when SSLv2 and SSlv3 are disabled (TLS only) (and greater)javax.net.ssl.SSLHandshakeException:当 SSLv2 和 SSlv3 被禁用(仅 TLS)(及更高版本)时,Android 5.0.0 上的握手失败
【发布时间】:2016-06-18 03:51:52
【问题描述】:

这是我的第一篇文章,我将尽力做到尽可能清晰(对不起我的英语)。

这是我的麻烦,我正在使用 retrofit:1.9.0 和 okhttp:2.7.5 来执行 API 调用。一切都很好,直到我的服务器提供商禁用 SLLv2 和 SSLv3 导致安全问题(3 月 1 日发现淹没失败)。

现在我检查了有关我的提供商的信息,他只允许来自https://www.ssllabs.com/ 的带有密码的 TLSv1 (TLS 1.0 TLS_RSA_WITH_3DES_EDE_CBC_SHA No FS)。

好的,这就是我所做的所有测试和结果:

[已解决更新问题]

在我的第二个答案中找到解决此问题的方法。

更新 似乎问题来自谷歌API版本。当我在 API 18 上进行测试时,一切正常。当它在大于或等于 5.0.0 的 Android 上失败。

第一次测试

会议。回顾:

  • compileSdkVersion 23
  • buildToolsVersion '23.0.2'
  • minSdkVersion 18
  • targetSdkVersion 21
  • 改造:1.9.0
  • okhttp:2.7.5
  • Android 版本 > 5.0.0(但在每台设备上都相同...)

休息客户端(LoginRestClient):

public class LoginRestClient
{
    private static final String BASE_URL = "";
    private LoginApiService apiService;

    public LoginRestClient()
    {
        Gson gson = new GsonBuilder()
                .setDateFormat("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSS'Z'")
                .create();

        RestAdapter restAdapter = new RestAdapter.Builder()
                .setLogLevel(RestAdapter.LogLevel.FULL)
                .setEndpoint(ApiIntentService.getHostAddress())
                .setConverter(new GsonConverter(gson))
                .setClient(new OkClient(ApiIntentService.getConnectionHttpClient()))
                .build();

        apiService = restAdapter.create(LoginApiService.class);
    }

    public LoginApiService getApiService() {
        return apiService;
    }
}

创建客户端函数 OkHttpClient getConnectionHttpClient()

public static OkHttpClient getConnectionHttpClient()
{
    OkHttpClient okHttpClient = new OkHttpClient();
    okHttpClient.setReadTimeout(60, TimeUnit.SECONDS);
    okHttpClient.setConnectTimeout(60, TimeUnit.SECONDS);



        ConnectionSpec specs = new ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS)
                .tlsVersions(TlsVersion.TLS_1_0)
                .cipherSuites(CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA)
                .build();

        okHttpClient.setConnectionSpecs(Collections.singletonList(specs));

    return okHttpClient;
}

自定义回调导致公共无效失败(RetrofitError 错误)

java.net.UnknownServiceException:无法找到可接受的协议。 isFallback=false, 模式=[ConnectionSpec(cipherSuites=[TLS_RSA_WITH_3DES_EDE_CBC_SHA], tlsVersions=[TLS_1_0], supportsTlsExtensions=true)], 支持的协议=[SSLv3, TLSv1, TLSv1.1, TLSv1.2]

第二次测试

我制作了一个自定义 SSLSocketFactory 来禁用 SSLv3 并强制使用 TLS:

/**
 * @author fkrauthan
 */
public class TLSSocketFactory extends SSLSocketFactory {

    private SSLSocketFactory internalSSLSocketFactory;

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

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

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

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

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

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

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

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

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

我是这样使用的:

public static OkHttpClient getConnectionHttpClient()
    {
        OkHttpClient okHttpClient = new OkHttpClient();
        okHttpClient.setReadTimeout(60, TimeUnit.SECONDS);
        okHttpClient.setConnectTimeout(60, TimeUnit.SECONDS);

        try {
            TLSSocketFactory tlsSocketFactory = new TLSSocketFactory();
            HttpsURLConnection.setDefaultSSLSocketFactory(tlsSocketFactory);
            okHttpClient.setSslSocketFactory(tlsSocketFactory);
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

 return okHttpClient;
}

自定义回调导致公共无效失败(RetrofitError 错误)

javax.net.ssl.SSLProtocolException: SSL 握手中止: ssl=0x7f87885280: SSL 库失败,通常是协议错误 错误:14077410:SSL 例程:SSL23_GET_SERVER_HELLO:sslv3 警报握手失败(外部/openssl/ssl/s23_clnt.c:770 0x7f87c2fdf0:0x00000000)

如果有人可以帮助我,那将非常酷。我所有的应用程序都关闭了,我从昨天早上开始就在与这个问题作斗争,以恢复我的服务。我正在一根一根地脱毛……

提前致谢。

【问题讨论】:

标签: java android ssl https retrofit


【解决方案1】:

如果你使用 OkHttpClient 使用

OkHttpClient.Builder client = new OkHttpClient.Builder();
client.connectionSpecs(Arrays.asList(ConnectionSpec.COMPATIBLE_TLS));

设置客户端时执行 client.build()。

【讨论】:

    【解决方案2】:

    检查您是否包含 https:// 而不是将 http:// 发送到您的服务器

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      • 太好了,它帮助了我!你知道kevzzz的解决方案有什么不同吗?几个月前它对我有用,但现在不再适用了。 Android框架有什么变化吗?无论如何,我很高兴找到了您的解决方案!
      • 在搜索了几天为什么有些手机无法连接后,这救了我
      【解决方案4】:

      问题已解决:

      大家好,经过三天三夜的战斗,这里是最终的解决方案。 所以感谢这里的解决方案:

      How to disable SSLv3 in android for HttpsUrlConnection?

      还有这个库:https://guardianproject.info/code/netcipher

      它允许在禁用 SSLv2 和 SSlv3 的情况下为 Android 提供更好的方式来使用密码和 TLS。

      首先创建此类 NoSSLv3SocketFactory.java 并通过创建这样的构造函数将其与 CypherUrl 连接耦合

      public NoSSLv3SocketFactory(URL sourceUrl) throws IOException {
              this.delegate = NetCipher.getHttpsURLConnection(sourceUrl).getDefaultSSLSocketFactory();
          }
      

      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.net.URL;
      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;
      
      import info.guardianproject.netcipher.NetCipher;
      
      
      public class NoSSLv3SocketFactory extends SSLSocketFactory{
          private final SSLSocketFactory delegate;
      
          public NoSSLv3SocketFactory(URL sourceUrl) throws IOException {
              this.delegate = NetCipher.getHttpsURLConnection(sourceUrl).getDefaultSSLSocketFactory();
          }
      
          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);
              }
          }
      }
      

      现在(在我的情况下是改造)就像这样使用它:

      首先,添加一个静态方法(或在使用时创建它)以使用我们之前创建的 NoSSlv3Factory.java 类创建一个 okHttpClient。

      public static OkClient createClient(int readTimeout, TimeUnit readTimeoutUnit, int connectTimeout, TimeUnit connectTimeoutUnit)
      {
          final OkHttpClient okHttpClient = new OkHttpClient();
          okHttpClient.setReadTimeout(readTimeout, readTimeoutUnit);
          okHttpClient.setConnectTimeout(connectTimeout, connectTimeoutUnit);
      
          try {
              URL url = new URL(ApiIntentService.getHostAddress());
              SSLSocketFactory NoSSLv3Factory = new NoSSLv3SocketFactory(url);
              okHttpClient.setSslSocketFactory(NoSSLv3Factory);
          } catch (MalformedURLException e) {
              e.printStackTrace();
          } catch (IOException e) {
              e.printStackTrace();
          }
      
          return new OkClient(okHttpClient);
      
      }
      

      那么,在我的情况下,当您创建 RestAdapter 时,只需将其设置为这样,并且不要忘记设置您的客户端。

      public class LoginRestClient
      {
          private static final String BASE_URL = "";
          private LoginApiService apiService;
      
          public LoginRestClient()
          {
              Gson gson = new GsonBuilder()
                      .setDateFormat("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSS'Z'")
                      .create();
      
              RestAdapter restAdapter = new RestAdapter.Builder()
                      .setLogLevel(RestAdapter.LogLevel.FULL)
                      .setEndpoint(ApiIntentService.getHostAddress())
                      .setConverter(new GsonConverter(gson))
                      .setClient(ApiIntentService.createClient(60, TimeUnit.SECONDS, 20, TimeUnit.SECONDS))
                      .build();
      
              apiService = restAdapter.create(LoginApiService.class);
          }
      
          public LoginApiService getApiService() {
              return apiService;
          }
      }
      

      有了这个它应该可以工作。 我希望它对其他人有用。

      【讨论】:

      猜你喜欢
      • 2018-03-04
      • 2017-06-21
      • 2016-04-08
      • 2017-09-20
      • 2014-12-09
      • 1970-01-01
      • 1970-01-01
      • 2015-12-06
      • 2017-08-16
      相关资源
      最近更新 更多