在Android 4.4中启用TLS 1.2

10

我使用Retrofit和OkHttp3进行请求。我知道在Android 4.4中,默认情况下未启用TLS 1.1和TLS 1.2。所以我正在尝试启用它们,但到目前为止没有成功。我读到说这可能是Android Studio模拟器的问题,但我现在无法在真实设备上测试Android 4.4。

以下是我迄今为止所做的:

private <S> S createService(Class<S> serviceClass) {
    Retrofit retrofit = builder.client(getNewHttpClient()).build();
    return retrofit.create(serviceClass);
}

private OkHttpClient getNewHttpClient() {
    OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
            .connectTimeout(10, TimeUnit.SECONDS)
            .writeTimeout(10, TimeUnit.SECONDS)
            .readTimeout(0, TimeUnit.MINUTES); // Disable timeouts for read

    return enableTls12OnPreLollipop(clientBuilder).build();
}


public static OkHttpClient.Builder enableTls12OnPreLollipop(OkHttpClient.Builder client) {
    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
        try {
            client.sslSocketFactory(new TLSSocketFactory());

            ConnectionSpec cs = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
                    .tlsVersions(TlsVersion.TLS_1_2)
                    .build();

            List<ConnectionSpec> specs = new ArrayList<>();
            specs.add(cs);
            specs.add(ConnectionSpec.COMPATIBLE_TLS);
            specs.add(ConnectionSpec.CLEARTEXT);

            client.connectionSpecs(specs);
        } catch (Exception exc) {
            Log.e("OkHttpClientProvider", "Error while enabling TLS 1.2", exc);
        }
    }

    return client;
}

TLSSocketFactory CLASS

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

我尝试了这个方法,但是没有成功。
我的错误信息是:javax.net.ssl.SSLProtocolException: SSL握手中止:ssl=0xb829bae0:SSL库中的故障,通常是协议错误:14077410:SSL例程:SSL23_GET_SERVER_HELLO:sslv3警报握手失败(external / openssl / ssl / s23_clnt.c:741 0x8d9e3990:0x00000000)

1
谢谢,这段代码解决了我的问题。 - Lawgrin Foul
2个回答

9
请尝试这个:https://developer.android.com/training/articles/security-gms-provider.html 。它使用了https://developers.google.com/android/reference/com/google/android/gms/security/ProviderInstaller,您需要在项目中安装 Google API。只需在应用程序中调用即可:
@Override
public void onCreate() {
    super.onCreate();
    try {
        ProviderInstaller.installIfNeeded(this);
    } catch (GooglePlayServicesRepairableException | GooglePlayServicesNotAvailableException e) {
        e.printStackTrace();
    }
}

你还应该删除自定义的SSL工厂。


我遇到了GooglePlayServicesNotAvailableException异常。这意味着我无法更新提供程序。可能是因为我正在使用未安装Google Play服务的模拟器?所以我必须要求那些未安装它的用户进行安装,对吗? - Fabio Piunti
可能是这样,不过最好的方法是在真实设备上进行测试。我认为用户应该得到适当的对话框,引导他们前往GooglePlay。 - Aleksander Mielczarek
如果Android设备上没有Google服务,这个解决方案就无法使用。 - undefined

3

当安卓从TLSv1回退到SSLv3时,通常会出现该错误。这是在lollipop之前的设备上的一个漏洞。

解决方法是使用安卓的安全提供程序移除SSLv3。

尝试这个解决方案:

private void updateAndroidSecurityProvider(Activity callingActivity) {
    try {
        ProviderInstaller.installIfNeeded(this);
    } catch (GooglePlayServicesRepairableException e) {
    GooglePlayServicesUtil.getErrorDialog(e.getConnectionStatusCode(), callingActivity, 0);
    } catch (GooglePlayServicesNotAvailableException e) {
        Log.e("SecurityException", "Google Play Services not available.");
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接