[TOC]
背景
对比http协议,https对传输内容进行加密,天然的支持防篡改,提升了安全性。
https架构
1576565338401.png
现在越来越多的服务器处于安全的考虑切换HTTPS协议,同时对于安全性较低的协议,TLS1.2以下的协议很多都取消了支持,但是andorid4.2设置是默认不开启TLS1.2,这块从官方文档可以得到信息。
Client socket:
Protocol
Supported (API Levels)
Enabled by default (API Levels)
SSLv3
1–25
1–22
TLSv1
1+
1+
TLSv1.1
16+
20+
TLSv1.2
16+
20+
TLSv1.3
29+
29+
异常
如果协议不支持,在请求的时候,是会报出下面的异常,异常会给出服务器支持的协议版本,已经当前系统套接字支持的版本。
java.net.UnknownServiceException: Unable to find acceptable protocols.
isFallback=false, modes=[ConnectionSpec(cipherSuites=[TLS_AES_128_GCM_SHA256,
TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_GCM_SHA256,
TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA,
SSL_RSA_WITH_3DES_EDE_CBC_SHA], tlsVersions=[TLS_1_3, TLS_1_2], supportsTlsExtensions=true),
ConnectionSpec()], supported protocols=[SSLv3, TLSv1]
既然官方文档上说android4.2是支持TLS1.0,TLS1.2的,只是默认不开启,那我们看看开启的方式。
TLS版本差别
详细的差别可以看下面链接的介绍,从这个差别可以看出一个信息,TLS版本的更新和加密套件是独立两套,加密套件是独立于TLS版本的内部处理逻辑的。
两者的关系类似于码头吊机和集装箱。
服务器TLS分析
1576572356964.png
开启TLS1.2
在开启TLS1.2之前,我们需要先熟悉一下android的javax.net.ssl包结构
javax.net.ssl属于java的jsse安全体系。
关于java安全体系方面的内容,可参考以下链接
1576568448756.png
对应jsse实现
/libcore/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/
1576569219527.png
类名称
类作用
SSLParameters
SSL连接相关的参数信息
SSLContext
SSLSocket协议实现的类,可以使用自定义的密钥管理,和证书管理进行初始化,通过这个实例获取套件字工厂
SSLSocketFactory
工厂方法模式,生成具体的SSLSocket
SSLSocket提供了设置安全协议版本,加密套件,启动握手等接口用于应用层调用
开启
核心方式就是替换成自定义的套件字工厂
在这里需要注意一下,不要直接设置一个自己创建的SSLSocketFactory,需要使用SSLContext创建的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() throws IOException {
return patch(delegate.createSocket());
}
@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 p