【问题标题】:SSL/TLS problems with Android 6+ clients, javax.net.ssl.SSLException: Inbound closed before receiving peer's close_notify: possible truncation attack?Android 6+ 客户端的 SSL/TLS 问题,javax.net.ssl.SSLException:入站在接收对等方的 close_notify 之前关闭:可能的截断攻击?
【发布时间】:2017-03-12 21:23:49
【问题描述】:

我有一个带有客户端服务器设置的多人游戏,它在桌面和我自己的 Android 测试设备(4.x - 5.x)上运行良好,但每个尝试过使用 Android 6+ 移动设备的人都不能完成与服务器的握手。

客户端获取:com.android.org.conscrypt.SSL_do_handshake(Native Method) 中的对等异常关闭连接

我在服务器上打开了 javax.net 包的完整输出,这就是我看到的:

Thread-5, called closeInbound()
Thread-5, fatal error: 80: Inbound closed before receiving peer's close_notify: possible truncation attack?
javax.net.ssl.SSLException: Inbound closed before receiving peer's close_notify: possible truncation attack?
%% Invalidated:  [Session-1, TLS_DHE_RSA_WITH_AES_128_CBC_SHA]
Thread-5, SEND TLSv1.2 ALERT:  fatal, description = internal_error
Thread-5, WRITE: TLSv1.2 Alert, length = 2
Thread-5, called closeOutbound()
Thread-5, closeOutboundInternal()

日志实际上是 90k+ 个字符,但我无法全部粘贴。但基本上服务器客户端经过 TLS1.2、1.1 和 1.0 并且结果是相同的“javax.net.ssl.SSLException: Inbound closed before received peer's close_notify: possible truncation attack?”

我正在使用自签名证书和信任库破解:

    public LoginClient() throws Exception{
             // Create a trust manager that does not validate certificate chains
            TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
//                      return null;
                        return new X509Certificate[0];
                    }
                    public void checkClientTrusted(X509Certificate[] certs, String authType) {
                    }
                    public void checkServerTrusted(X509Certificate[] certs, String authType) {
                    }
                }
            };

            // Install the all-trusting trust manager
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

            // Create all-trusting host name verifier
            HostnameVerifier allHostsValid = new HostnameVerifier() {
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            };

            // Install the all-trusting host verifier
            HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);

        }

有谁知道出了什么问题以及我该如何解决这个问题?我觉得有点奇怪,它只发生在 Android 6+ 上

编辑:添加了 *** Diffie-Hellman ServerKeyExchange

DH Modulus:  { 233, 230, 66, 89, 157, 53, 95, 55, 201, 127, 253, 53, 103, 18, 11, 142, 37, 201, 205, 67, 233, 39, 179, 169, 103, 15, 190, 197, 216, 144, 20, 25, 34, 210, 195, 179, 173, 36, 128, 9, 55, 153, 134, 157, 30, 132, 106, 171, 73, 250, 176, 173, 38, 210, 206, 106, 34, 33, 157, 71, 11, 206, 125, 119, 125, 74, 33, 251, 233, 194, 112, 181, 127, 96, 112, 2, 243, 206, 248, 57, 54, 148, 207, 69, 238, 54, 136, 193, 26, 140, 86, 171, 18, 122, 61, 175 }
DH Base:  { 48, 71, 10, 213, 160, 5, 251, 20, 206, 45, 157, 205, 135, 227, 139, 199, 209, 177, 197, 250, 203, 174, 203, 233, 95, 25, 10, 167, 163, 29, 35, 196, 219, 188, 190, 6, 23, 69, 68, 64, 26, 91, 44, 2, 9, 101, 216, 194, 189, 33, 113, 211, 102, 132, 69, 119, 31, 116, 186, 8, 77, 32, 41, 216, 60, 28, 21, 133, 71, 243, 169, 241, 162, 113, 91, 226, 61, 81, 174, 77, 62, 90, 31, 106, 112, 100, 243, 22, 147, 58, 52, 109, 63, 82, 146, 82 }
Server DH Public Key:  { 23, 79, 111, 200, 124, 159, 143, 170, 244, 139, 127, 154, 15, 184, 207, 89, 0, 30, 234, 138, 254, 90, 48, 244, 171, 46, 100, 55, 220, 87, 23, 2, 3, 243, 132, 144, 17, 75, 191, 90, 239, 112, 13, 71, 150, 127, 34, 219, 174, 161, 188, 204, 151, 97, 179, 129, 103, 89, 188, 211, 14, 216, 71, 115, 12, 105, 63, 219, 23, 70, 110, 231, 202, 153, 121, 59, 194, 97, 105, 215, 57, 211, 48, 184, 22, 149, 176, 64, 186, 103, 240, 237, 224, 217, 233, 4 }
Signature Algorithm SHA512withRSA
Signed with a DSA or RSA public key
*** ServerHelloDone

更新 我终于拿到了一个 Android 6.0.1 设备,所以我可以再测试一下。 在我的开发环境中,我在生产服务器上运行 Oracle Java 7u25,有 openjdk 7,有趣的是,Android 6 在我的开发环境中使用完全相同的设置工作,但是当我尝试连接到生产服务器时失败。我现在可以看到完整的异常,它是:

11-01 05:18:50.793: W/System.err(23793): javax.net.ssl.SSLHandshakeException: Handshake failed
11-01 05:18:50.796: W/System.err(23793):    at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:396)
11-01 05:18:50.796: W/System.err(23793):    at com.android.okhttp.internal.http.SocketConnector.connectTls(SocketConnector.java:103)
11-01 05:18:50.796: W/System.err(23793):    at com.android.okhttp.Connection.connect(Connection.java:143)
11-01 05:18:50.796: W/System.err(23793):    at com.android.okhttp.Connection.connectAndSetOwner(Connection.java:185)
11-01 05:18:50.796: W/System.err(23793):    at com.android.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:128)
11-01 05:18:50.796: W/System.err(23793):    at com.android.okhttp.internal.http.HttpEngine.nextConnection(HttpEngine.java:341)
11-01 05:18:50.796: W/System.err(23793):    at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:330)
11-01 05:18:50.796: W/System.err(23793):    at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:248)
11-01 05:18:50.796: W/System.err(23793):    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:437)
11-01 05:18:50.796: W/System.err(23793):    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:114)
11-01 05:18:50.796: W/System.err(23793):    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:245)
11-01 05:18:50.797: W/System.err(23793):    at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getOutputStream(DelegatingHttpsURLConnection.java:218)
11-01 05:18:50.797: W/System.err(23793):    at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java)
11-01 05:18:50.797: W/System.err(23793):    at com.aperico.game.sylvass.netcode.LoginClient.doLogin(LoginClient.java:105)
11-01 05:18:50.797: W/System.err(23793):    at com.aperico.game.sylvass.CryptCardsGame$4.run(CryptCardsGame.java:343)
11-01 05:18:50.797: W/System.err(23793):    at java.lang.Thread.run(Thread.java:818)
11-01 05:18:50.797: W/System.err(23793):    Suppressed: javax.net.ssl.SSLHandshakeException: Handshake failed
11-01 05:18:50.797: W/System.err(23793):        ... 16 more
11-01 05:18:50.797: W/System.err(23793):        Suppressed: javax.net.ssl.SSLHandshakeException: Handshake failed
11-01 05:18:50.797: W/System.err(23793):            ... 16 more
11-01 05:18:50.798: W/System.err(23793):        Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x941df080: Failure in SSL library, usually a protocol error
11-01 05:18:50.798: W/System.err(23793): error:100c1069:SSL routines:ssl3_get_server_key_exchange:BAD_DH_P_LENGTH (external/boringssl/src/ssl/s3_clnt.c:1193 0xa9e31ad5:0x00000000)
11-01 05:18:50.798: W/System.err(23793):            at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
11-01 05:18:50.798: W/System.err(23793):            at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:324)
11-01 05:18:50.798: W/System.err(23793):            ... 15 more
11-01 05:18:50.798: W/System.err(23793):    Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x941df080: Failure in SSL library, usually a protocol error
11-01 05:18:50.798: W/System.err(23793): error:100c1069:SSL routines:ssl3_get_server_key_exchange:BAD_DH_P_LENGTH (external/boringssl/src/ssl/s3_clnt.c:1193 0xa9e31ad5:0x00000000)
11-01 05:18:50.798: W/System.err(23793):        at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
11-01 05:18:50.799: W/System.err(23793):        at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:324)
11-01 05:18:50.799: W/System.err(23793):        ... 15 more
11-01 05:18:50.799: W/System.err(23793): Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x941df080: Failure in SSL library, usually a protocol error
11-01 05:18:50.799: W/System.err(23793): error:100c1069:SSL routines:ssl3_get_server_key_exchange:BAD_DH_P_LENGTH (external/boringssl/src/ssl/s3_clnt.c:1193 0xa9e31ad5:0x00000000)
11-01 05:18:50.799: W/System.err(23793):    at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
11-01 05:18:50.799: W/System.err(23793):    at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:324)
11-01 05:18:50.799: W/System.err(23793):    ... 15 more

【问题讨论】:

  • 如果您有效地禁用了证书验证,为什么还要使用 SSL?除此之外,它可能是一个弱 DH 密钥,但没有足够的详细信息(如服务器名称)来查找。
  • @SteffenUllrich 没有服务器名称只有 IP 所以我不能使用 ssllabs.com 例如。我可以提供任何需要的信息,但由于大小限制,我无法一次粘贴所有信息。我在上面的编辑中添加了 DH 详细信息。

标签: java android ssl tls1.2


【解决方案1】:

在服务器上更新到 Oracle Java 8 解决了这个问题。不完全确定为什么,但似乎 Android 6+ 无法与 openjdk 7 协商握手

【讨论】:

    【解决方案2】:

    服务器 DH 公钥:{ ... 0 到 255 之间的 96 个数字 ... }

    您的 DH 密钥只有 768 位 (96*8)。这被认为是弱的,有关详细信息,请参阅logjam attack。因此,包括大多数现代 Web 浏览器在内的现代 TLS 堆栈要求 DH 密钥至少为 1024 位。

    我的猜测是你在服务器上使用 Java 7,因为768 bit DH key is the default there,而使用 Java 8 默认是 1024 位。 根据How Java 7 and 8 Handle DHE Keys Differently, and Resolving Errors,Java 7 不能使用 1024 位或更好的 DH 密钥,这意味着您的选择是升级到 Java 8 或禁用使用 DH 的密码。后者如何做,本文也有介绍。

    除此之外,像您一样在客户端禁用主机名验证是一个非常糟糕的主意。这实际上意味着您信任由受信任的 CA 颁发的任何证书,无论该证书对哪个主机有效。 这使得中间人攻击变得容易,从而有效地消除了 TLS 提供的保护的主要部分。如果您有一个无法信任的证书,请使用证书固定来在您的应用程序中仅接受此证书并阻止中间人攻击。请参阅OWASP 了解更多信息,包括适用于包括 Java 在内的多种语言的示例代码。

    【讨论】:

    • 好的,谢谢我在服务器上使用 j7,并将尝试这个解决方案。也感谢您指出安全问题,我知道这些但尚未决定如何插入它们。使用 HttpsURLConnection.setDefaultHostnameVerifier(myHostIPOnly);我猜这还不够吗?
    • @Korpen:如果您有此特定 IP 地址的有效证书,则限制主机名验证程序以确保该 IP 地址必须包含在证书中,只要没有人能够也获得此 IP 地址的证书。但是,通常您不会获得 IP 地址的证书(至少不是来自公共 CA),除此之外,IP 地址很有可能在未来发生变化。
    • 我尝试更改您在上面给出的链接中描述的允许密码。服务器日志现在使用 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 显示它,但它仍然不适用于使用 Android 6.0 的测试人员。我还看到了一些我错过的东西,例如,当我从我的 Win7/64 机器登录时,它首先尝试使用 TLSv1.2,但服务器日志仍然显示“javax.net.ssl.SSLException: Inbound closed在收到对等方的 close_notify 之前:可能的截断攻击?”留言
    • Win7的问题可能是因为客户端收到无效证书而关闭,一旦用户添加异常就会重新连接。如果您的服务器是公共可访问的,并且您可以提供其 URL,那么您可能会发现更多有关该问题的信息。
    • 在 Win7 上它确实有效,它只是给出了关于可能的截断攻击的相同警告。我发现可以测试 ip 地址的 sslshopper.com,它说证书很好。我已经更新了我的问题,请看一下,看看您是否还能想到什么?
    猜你喜欢
    • 2019-09-25
    • 2019-04-07
    • 1970-01-01
    • 2019-05-17
    • 2019-03-27
    • 2021-10-25
    • 1970-01-01
    • 2018-07-31
    • 1970-01-01
    相关资源
    最近更新 更多