2

我正在尝试从没有 Internet 连接的网络中使用 10.10.10.2 的 Android 主机向主机 10.10.10.1 执行 HTTPS 请求 - 只有 WiFi 2 对等 AP 和 Android 9 Google Pixel One 设备。

network_security_config.xml使用自签名的证书创建了 CN=10.10.10.1 和 SAN= DNS: 10.10.10.1 PI: 10.10.10.1。

<?xml version="1.0" encoding="utf-8"?>
  <network-security-config>
    <base-config cleartextTrafficPermitted="true">
      <trust-anchors>
        <certificates src="system" />
        <certificates src="user" />
        <certificates src="@raw/zone"/>
      </trust-anchors>
    </base-config>
</network-security-config>

我没有收到验证错误并观察到成功的请求传入服务器 - 数据是 HTTP 请求,已解密并显示在服务器日志上。但是服务器无法发回数据!它发送,但由于某种原因,Android 手机不接受这些数据 - 只是被忽略了。

我看到数据包正在从服务器发送到电话,并且服务器反复重试关闭 SSL 套接字,直到错误或成功(我在调查期间故意做出这种行为) - 这是来自 WiFi 空气的 Wireshark 转储:

Wireshark 转储

这是我来自 AsyncTask 的请求

   protected String doInBackground(String... params) {
        StringBuilder result = new StringBuilder();
        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            InputStream caInput = new BufferedInputStream(MainActivity.this.getResources().openRawResource(R.raw.zone));

            Certificate ca = cf.generateCertificate(caInput);

            String keyStoreType = KeyStore.getDefaultType();
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);

            String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
            tmf.init(keyStore);

            SSLContext ctx = SSLContext.getInstance("TLS");
            ctx.init(null, tmf.getTrustManagers(), null);

            URL url = new URL("https://10.10.10.1/connect");
            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
            conn.setSSLSocketFactory(ctx.getSocketFactory());

            conn.setRequestProperty("param1", params[0]);
            conn.setRequestProperty("param2", params[1]);
            conn.setRequestMethod("POST");

            conn.setDoOutput(true);
            conn.setDoInput(true);

            mInputStream = conn.getInputStream();
            byte[] buffer = new byte[1024];
            ByteArrayOutputStream _buf = new ByteArrayOutputStream();
            int l;
            BufferedInputStream bufin = new BufferedInputStream(mInputStream);
            while ((l = bufin.read(buffer,0,1024)) != -1) {
                _buf.write(buffer, 0, l);
                String rec = _buf.toString("UTF-8");
                Log.d("MAIN", "Read: " + rec);
                result.append(rec);
            }
            Log.d("MAIN", "Read finished: " + result.toString());

        } catch (Exception e) {
            e.printStackTrace();
        }
        return result.toString();
    }

我怀疑 Android 9 Network Security 确实会以某种方式阻止流量。我尝试使用 SSLSockets,将端口从 443 更改为例如 1234 - 不走运。

事实上,我的应用程序是用 Qt 创建的,首先我使用了 Qt 的东西,但没有运气 - 我在 MainActivity 中回退到 Android Java 代码,我通过 Qt 代码中的 JNI 调用。结果是一样的,我没有更多的想法......

在哪里挖?

UPD1

当使用仅包含(无 IP:10.10.10.1)的 SAN 生成自签名证书时,DNS:10.10.10.1SSL 失败并显示警告:

W System.err: javax.net.ssl.SSLPeerUnverifiedException: Hostname 10.10.10.1 not verified:
W System.err:     certificate: sha1/gyr2GOhy5lA+ZAHEzh0E2SBEgx0=
W System.err:     DN: CN=10.10.10.1,O=Some ltd.,L=Knoxville,ST=TN,C=US
W System.err:     subjectAltNames: [10.10.10.1]
W System.err:   at com.android.okhttp.internal.io.RealConnection.connectTls(RealConnection.java:201)
W System.err:   at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:149)
W ...

相反,使用 SAN IP:10.10.10.1(没有 DNS:10.10.10.1) - 像以前一样工作 - 会话建立,数据传输到服务器并解密,但从服务器到客户端的响应只是被客户端忽略。

UPD2

我还尝试将域名some.device用于 10.10.10.1 设备,并使用 CN 和 SAN DNS = some.device 颁发证书。它已由 Android 9 客户端解决,数据发送成功,但响应仍未被接受。

看起来像Android错误。

4

1 回答 1

0

进行额外调查后: 1. 包括Pixel 1在内的部分Android设备(build)不接受没有通过相互[FIN,ACK]最终确定的TCP会话,并且接收到的数据没有传递到上层堆栈。此外,如果 TCP 流不可靠,数据可能不被接受,许多重传和 Seq 发生变化。2. 如果使用 Qt - Android Network Security Configuration 不影响通信。3. 这不是 TLS 相关的问题。

于 2019-01-13T07:54:59.803 回答