我最近在服务器端关闭了对TLS 1.0和1.1的支持,所有的Android应用程序都停止工作。 我知道Android 4及以下版本不支持TSL 1.2或更高版本,但即使是在Android 10上运行的应用程序也停止工作。 手机上的栈跟踪显示TLS问题。 安装在iphones上的应用没有看到任何问题。 当我们启用支持TLS 1.0和1.1的Android应用在所有Android手机上都能正常运行,但是服务器的安全审计却出现了问题。 在Android操作系统中是否有什么东西可以启用对TLS 1.2的支持?
我最近也遇到了同样的问题,在网上看了一下,在你的当前可能有多个地方会出现通话失败的情况,即使是在最近的安卓版本上。然而,你可以做两个主要的步骤,以确保你的应用程序是准备TLS 1.2。
确保使用Google Play服务,并启用安全服务(com.google.android.gms.security.ProviderInstaller
). 你必须在你的代码中这样做 之前 你创建任何HttpClient资源(否则他们将使用一个旧的安全规范)有这样的东西在 onCreate
你的主要活动的应该很好地工作。
try {
ProviderInstaller.installIfNeeded(this);
Log.i(LOG_TAG, "Google Play Services Installed");
} catch (GooglePlayServicesRepairableException e) {
GoogleApiAvailability.getInstance()
.showErrorNotification(this, e.getConnectionStatusCode());
Log.i(LOG_TAG, "Error", e);
} catch (GooglePlayServicesNotAvailableException e) {
Log.i(LOG_TAG, "Error", e);
}
重要的是要有这种运行 之前 创建任何http客户端,否则它们将不支持TLS 1.2。
确保在你的HttpClient中启用了TLS 1.2。有些客户端的默认配置没有启用TLS 1.2。例如对于OkHttp,你应该创建以下SocketFactory。
import android.os.Build;
import android.util.Log;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import okhttp3.CipherSuite;
import okhttp3.ConnectionSpec;
import okhttp3.OkHttpClient;
import okhttp3.TlsVersion;
/**
* Enables TLS v1.2 when creating SSLSockets.
* <p/>
* For some reason, android supports TLS v1.2 from API 16, but enables it by
* default only from API 20.
* @link https://developer.android.com/reference/javax/net/ssl/SSLSocket.html
* @see SSLSocketFactory
*/
public class Tls12SocketFactory extends SSLSocketFactory {
private static final String[] TLS_V12_ONLY = {"TLSv1.2"};
final SSLSocketFactory delegate;
public Tls12SocketFactory(SSLSocketFactory base) {
this.delegate = base;
}
@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 patch(delegate.createSocket(s, host, port, autoClose));
}
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
return patch(delegate.createSocket(host, port));
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
return patch(delegate.createSocket(host, port, localHost, localPort));
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return patch(delegate.createSocket(host, port));
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return patch(delegate.createSocket(address, port, localAddress, localPort));
}
private Socket patch(Socket s) {
if (s instanceof SSLSocket) {
((SSLSocket) s).setEnabledProtocols(TLS_V12_ONLY);
}
return s;
}
private static final CipherSuite[] APPROVED_CIPHER_SUITES = new CipherSuite[] {
// TLSv1.3
CipherSuite.TLS_AES_128_GCM_SHA256,
CipherSuite.TLS_AES_256_GCM_SHA384,
CipherSuite.TLS_CHACHA20_POLY1305_SHA256,
CipherSuite.TLS_AES_128_CCM_SHA256,
CipherSuite.TLS_AES_256_CCM_8_SHA256,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
// Note that the following cipher suites are all on HTTP/2's bad cipher suites list. We'll
// continue to include them until better suites are commonly available. For example, none
// of the better cipher suites listed above shipped with Android 4.4 or Java 7.
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384,
CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA,
CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
};
public static OkHttpClient.Builder enableTls12OnPreLollipop(OkHttpClient.Builder client) {
if (Build.VERSION.SDK_INT < 22) {
try {
SSLContext sc = SSLContext.getInstance("TLSv1.2");
sc.init(null, null, null);
client.sslSocketFactory(new Tls12SocketFactory(sc.getSocketFactory()));
ConnectionSpec cs = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.cipherSuites(APPROVED_CIPHER_SUITES)
.tlsVersions(TlsVersion.TLS_1_3, TlsVersion.TLS_1_2)
.supportsTlsExtensions(true)
.build();
List<ConnectionSpec> specs = new ArrayList<>();
specs.add(cs);
client.connectionSpecs(specs);
Log.i("OkHttpTLSCompat", "TLS 1.2 enabled");
} catch (Exception exc) {
Log.e("OkHttpTLSCompat", "Error while setting TLS 1.2", exc);
}
}
return client;
}
public static OkHttpClient returnClient() {
OkHttpClient.Builder client = new OkHttpClient.Builder()
.followRedirects(true)
.followSslRedirects(true)
.retryOnConnectionFailure(true)
.cache(null)
.connectTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS);
return enableTls12OnPreLollipop(client).build();
}
}
然后执行 Tls12SocketFactory.returnClient()
当你需要
重要的是,你需要同时启用这两个功能! 如果没有Google Play安全服务,无论你使用的是什么http库,你都无法在旧的Android设备上获得TLS 1.2支持。而且确保在HttpClient中也启用了TLS也是很重要的。
另外让我重申一下,在你创建任何http客户端之前,加载Google Play更新是很重要的。我最近花了点时间来调试这个问题,因为在我的代码中,一些库在我放入Google Play代码之前已经被初始化了,因此它们没有得到TLS 1.2的支持。