ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

改进:在API21设备上启动时,Android应用失败了SSL握手

2019-10-26 09:26:28  阅读:251  来源: 互联网

标签:ssl retrofit okhttp handshake android


我正在构建一个使用Retrofit和自定义OkHttp客户端通过HTTPS获取一些JSON数据的应用程序.它可以在KitKat上正常工作.一旦我转到Android 5、6或7,SSL握手就会失败.

服务器支持TLSv1,仅此一项.它还使用古老的,过期的,自签名证书.使用Qualys的SSL工具进行了测试,该工具告诉我所有版本的Android都可以连接.这是我得到的:

OkHttp客户端:

public class HTTPClient {

public static OkHttpClient getUnsafeOkHttpClient() {
    try {
        // Create a trust manager that does not validate certificate chains

        final TrustManager[] trustAllCerts = new TrustManager[] {
                new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                    }

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

                    @Override
                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        return new java.security.cert.X509Certificate[]{};
                    }
                }
        };

        // Install the all-trusting trust manager
        final SSLContext sslContext = SSLContext.getInstance("TLSv1");
        sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
        // Create a ssl socket factory with our all-trusting manager
        final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
        //URL url = new URL(ApiIntentService.getHostAddress());
        //final SSLSocketFactory sslSocketFactory = new NoSSLv3SocketFactory(url);

//            ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.COMPATIBLE_TLS)
//                    .tlsVersions(TlsVersion.TLS_1_0)
//                    .cipherSuites(
//                            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
//                            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
//                            CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
//                            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
//                            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
//                            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
//                            CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
//                            CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
//                            CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
//                            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA)
//                    .build();

//            String hostname = "api.server.domain";
//            CertificatePinner certificatePinner = new CertificatePinner.Builder()
//                    .add(hostname, "sha256/3Iiwgs3a0qjPCnBQzW/GeHhPbZvhaJtxKvMJJVO5KdU=")
//                    .build();

        final OkHttpClient.Builder builder = new OkHttpClient.Builder();
//            builder.connectionSpecs(Collections.singletonList(spec));
//            builder.certificatePinner(certificatePinner);
            builder.sslSocketFactory(sslSocketFactory);
            builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
            builder.authenticator(new Authenticator() {
                @Override
                public Request authenticate(Route route, Response response) throws IOException {
                    String credential = Credentials.basic("user", "pass");
                    return response.request().newBuilder()
                            .header("Authorization", credential)
                            .build();
                }
            });
        OkHttpClient okHttpClient = builder.build();
        return okHttpClient;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

我知道此代码在安全性方面是多么可怕.我的主管要求这样做.我告诉他这有多严重.

我已经尝试了两种方法来解决我的问题,它们在那段代码中已被注释掉-证书固定和请求TLSv1以及特定的密码列表.在其他问题中找到了这两个,但是它们什么也没改变(堆栈跟踪完全相同).

堆栈跟踪

以下是堆栈跟踪的有趣内容:

I/RETROFIT: Data retrieval failed! javax.net.ssl.SSLHandshakeException: Handshake failed
*snip*
Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb43eb200: Failure in SSL library, usually a protocol error
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:770 0xac6fedd4:0x00000000)
                at       com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)

似乎Android突然尝试使用SSLv3,但Wireshark显示通过TLSv1的通信.它以应有的客户端Hello开头,但是服务器会立即以握手失败响应(40).

因为我全都没主意,所以极大地感谢了所有帮助.请要求是否需要澄清.

谢谢.

解决方法:

告诉主管,您的HTTP客户端无法连接到严重不安全的HTTPS服务器.您可以说这是计算机的限制,唯一的选择是更新服务器.

完成后,您可以添加仅开发调试模式.为此,请启用服务器支持的密码套件.您可以从Qualys工具中获取列表.

标签:ssl,retrofit,okhttp,handshake,android
来源: https://codeday.me/bug/20191026/1935286.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有