TLSv1.2升级方案讨论
实际上在这次需求之前,我都没有遇到过这方便的需求,了解的也比较少。我是比较佩服我们后台的,我们后台比较霸气,直接在生产环境就升级了后台的协议,而且是只支持TLSv1.2版本。当然最终导致的问题是所有接口都失效了,然后就开始甩锅。我更新了这个是为了整个项目安全,但现在你看看在Ios上面运行没有问题,在Android上面出现了问题,你们Android开发是怎么办事的,略略略。。。
好废话少说我们先进正题。这个是在https要求下的协议对应版本,ps:下面的图片摘自 【csdn严振杰】
从表上我们可以发现,实际上16+以后我们就支持了TLSv1.2,而TLSv1.2在20+的版本才被启用。这说明在Android16+的版本我们支持了TLSv1.2,但是系统默认使用的是TLSv1.0。这里需要我们支持TLSv1.2,按照支持表,给SSLSocket设置默认使用TLSv1.2版本就可以了。
TLSv1.2方案验证一
重写SSLSocketFactory,setEnabledProtocols ,TLSv1.2
class Tls12SocketFactory extends SSLSocketFactory {
private final String[] TLS_SUPPORT_VERSION = {"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_SUPPORT_VERSION);
}
return s;
}
}
然而我用模拟器测试并卵用,找不到4.4的手机了。
TLSv1.2方案验证二
我就想到是不是SSLContext没有设置对,我换用了一种全面点的写法
public class TLSSocketFactory extends SSLSocketFactory {
private static final String PROTOCOL_ARRAY[];
static {
// https://developer.android.com/about/versions/android-5.0-changes.html#ssl
// https://developer.android.com/reference/javax/net/ssl/SSLSocket
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
PROTOCOL_ARRAY = new String[]{"TLSv1", "TLSv1.1", "TLSv1.2"};
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
PROTOCOL_ARRAY = new String[]{"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"};
} else {
PROTOCOL_ARRAY = new String[]{"SSLv3", "TLSv1"};
}
}
private static final X509TrustManager DEFAULT_TRUST_MANAGERS = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
// Trust.
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
// Trust.
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};
private static void setSupportProtocolAndCipherSuites(Socket socket) {
if (socket instanceof SSLSocket) {
((SSLSocket) socket).setEnabledProtocols(PROTOCOL_ARRAY);
}
}
private SSLSocketFactory delegate;
public TLSSocketFactory() {
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{DEFAULT_TRUST_MANAGERS}, new SecureRandom());
delegate = sslContext.getSocketFactory();
} catch (GeneralSecurityException e) {
throw new AssertionError(); // The system has no TLS. Just give up.
}
}
public TLSSocketFactory(SSLSocketFactory factory) {
this.delegate = factory;
}
@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 {
Socket ssl = delegate.createSocket(s, host, port, autoClose);
setSupportProtocolAndCipherSuites(ssl);
return ssl;
}
@Override
public Socket createSocket(String host, int port) throws IOException {
Socket ssl = delegate.createSocket(host, port);
setSupportProtocolAndCipherSuites(ssl);
return ssl;
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
Socket ssl = delegate.createSocket(host, port, localHost, localPort);
setSupportProtocolAndCipherSuites(ssl);
return ssl;
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
Socket ssl = delegate.createSocket(host, port);
setSupportProtocolAndCipherSuites(ssl);
return ssl;
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
Socket ssl = delegate.createSocket(address, port, localAddress, localPort);
setSupportProtocolAndCipherSuites(ssl);
return ssl;
}
@Override
public Socket createSocket() throws IOException {
Socket ssl = delegate.createSocket();
setSupportProtocolAndCipherSuites(ssl);
return ssl;
}
}
好吧,模拟器依然不识别,报错信息如下:
Error-javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb85e6050: Failure in SSL library, usually a protocol
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:741 0x84db0770:0x00000000)
结论
暂时我选择的版本升级到20+,甲方目前也接受。从后台统计的用户使用情况可以看出,用户的Android版本几乎在23+。只是有个梗卡着。如果有4.4真机的童鞋,麻烦下面留个言,看看方案是否通过。