记录两次Android 4.X设备SSL握手异常排查

第一次出现问题:

问题描述

       公司进行中台化改造,然后我们在调用Serverless服务的时候发现Android4.x设备出现了SSLHandshakeException


原因分析:

    经过查阅资料初步怀疑我们的Serverless最低只兼容TLS1.1,而Android4.X设备没有开启TLS1.1,TLS1.2版本的协议所导致。

Android4.2设备默认支持以下的 SSL/TLS 协议版本:

  1. SSLv3
  2. TLSv1
  3. TLSv1.1(不是默认启用,需要在代码中明确使用)
  4. TLSv1.2(不是默认启用,需要在代码中明确使用)

解决方案:

        如果是协议版本不匹配,那么在请求的时候打开Android的TLS1.1和TLS1.2不就行了吗?于是Android使用OkHttp为例,在构建HttpClient的时候打开TLS1.1和TLS1.2:

    private X509TrustManager xtm = new X509TrustManager() {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) {
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[]{};
        }
    };

new OkHttpClient.Builder()
 .sslSocketFactory(new TLSSocketFactory(xtm), xtm).build();

TLSSocketFactory类里面代码:


public class TLSSocketFactory extends SSLSocketFactory {

    private SSLSocketFactory delegate;

    public TLSSocketFactory(X509TrustManager xtm) throws KeyManagementException, NoSuchAlgorithmException {
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, new TrustManager[]{xtm}, new SecureRandom());
        delegate = context.getSocketFactory();
    }

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

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

    @Override

    public Socket createSocket() throws IOException {
        return enableTLSOnSocket(delegate.createSocket());

    }

    @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 {
        return enableTLSOnSocket(delegate.createSocket(host, port));

    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
        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 instanceof SSLSocket) {
            ((SSLSocket) socket).setEnabledProtocols(new String[]{"TLSv1.1", "TLSv1.2"});
        }
        return socket;
    }
}

第二次出现问题:

问题描述

        最近在进行老服务到新服务的迁移,在迁移之后,我们使用Adnroid4.X设备的用户再次出现的网络异常的现象,具体的报错信息: 

Connection error: javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSLhandshake aborted: ssl=0xb8e394a0: Failure in SSL library,usually a protocol error  error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol


原因分析:

        刚开始以为和之前碰到的问题一样,所以也就一直往这方面排查,然后经过测试发现并不是一样的情况。于是,开始在指定的设备进行网络抓包分析:

         在使用Wireshark进行抓包分析,发现在SSL握手的过程中没有server hello,直接就 Handshake Failure:

而正常的TLS1.2握手过程是这样的:

记录两次Android 4.X设备SSL握手异常排查_第1张图片

        然后我们更换Android5.0进行测试,发现一切正常,经过对Android4.2的请求和Android5.0的请求进行对比发现他们所支持的Cipher Suite加密套件不一样,Android5.0设备在进行TLS握手的时候服务端选择的是:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

        下图是客户端在进行Client Hello的时候向服务端发送自身所支持的加密套件:

记录两次Android 4.X设备SSL握手异常排查_第2张图片

        下图是服务端在Server Hello的时候与客户端匹配的加密套件:

记录两次Android 4.X设备SSL握手异常排查_第3张图片

  而在Android4.2的设备上发现所支持的加密套件少了好多:

记录两次Android 4.X设备SSL握手异常排查_第4张图片

        到这里大概能知道什么原因了, 当客户端和服务器建立 SSL 连接时,会协商并选择可用的密码套件。双方会根据优先级选择共同支持的加密算法、认证算法和密钥交换算法,并使用选定的密码套件来进行加密通信。Android4.2的设备在进行网络请求的时候TLS握手阶段提供的密码套件与服务端所支持的密码套件匹配不上。

解决方案:

        新服务添加相兼容的加密套件,添加TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA以后,恢复正常。

记录两次Android 4.X设备SSL握手异常排查_第5张图片

你可能感兴趣的:(android,ssl,网络,网络协议)