android - 以编程方式记录 SSL 证书
问题描述
我有 2 台设备无法连接到我的 TLS v1.2 端点。所有其他似乎都可以,包括浏览器、PostMan 和 iOS 设备。
这些设备运行的是 Android 5 和 7(因此TLS v1.2 支持应该没有问题)。
注意:这不是自签名证书。它由亚马逊签署。
直接的想法是:
Android 碎片 - 也许设备(一个是 Kindle Fire 7)没有将正确的证书包含到操作系统中。这不是设备制造商第一次做出破坏功能的奇怪决定。
API 是通过代理访问的,实际上有一个中间人,被正确检测到。
修复 (1) 意味着捆绑我们的证书,并在我们的证书过期时导致通常的问题。
我更愿意让用户安装一个调试版本,以确认 (1) 还是 (2) 是问题所在。这样的构建将检查服务器/代理提供的 SSL 证书,并将其记录回给我。
网络框架:
- 改造 v2.3.0
- OkHttp v3.9.1
问题:
如何检查设备在访问我的端点时看到的 SSL 证书的信息?
更新来自@SangeetSuresh 的每条评论:
事实证明,有 2 个不同的异常被抛出。
Kindle Fire 7" 平板电脑(KFAUWI,OS 5.1.1)正在抛出我已经开始调查的那个,这个问题的重点是。即基本的 SSL 故障。
java.security.cert.CertPathValidatorException:
Trust anchor for certification path not found.
at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:331)
at com.android.org.conscrypt.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:232)
at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:114)
LG 设备(LG-SP200,OS 7.1.2)的连接已被对等方关闭,如果此处未解决,则应在新问题下解决:
javax.net.ssl.SSLHandshakeException:
Connection closed by peer
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(NativeCrypto.java)
at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:360)
at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:299)
解决方案
Robby Cornelissen在引用 OkHttp的评论中提供了基本答案Response
:
信息应可从
response.handshake().peerCertificates()
.
给定有效的握手,实现了一个简单Interceptor
的检查证书:
private static class SslCertificateLogger implements Interceptor {
public static final String TAG = "SSL";
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response;
try {
response = chain.proceed(request);
} catch (Exception e) {
Log.d(TAG, "<-- HTTP FAILED: " + e);
throw e;
}
Handshake handshake = response.handshake();
if (handshake == null) {
Log.d(TAG, "no handshake");
return response;
}
Log.d(TAG, "handshake success");
List<Certificate> certificates = handshake.peerCertificates();
if (certificates == null) {
Log.d(TAG, "no peer certificates");
return response;
}
String s;
for (Certificate certificate : certificates) {
s = certificate.toString();
Log.d(TAG, s);
}
return response;
}
}
这被添加到OkHttpClient
正常情况下:
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.addInterceptor(new SslCertificateLogger())
.build();
Sangeet Suresh提出了一个类似的解决方案,它引用了 RetrofitResponse
对象:
response?.raw()?.handshake()
我想这会对你有所帮助
这里的重要信息是 Retrofit 以这种方式提供对原始 OkHttp 响应的访问。
在从 API获取 Retrofit 之后,这不会Interceptor
在实际的 Retrofit 处理代码中使用,而是在更高级别使用。Response<>
将他的 Kotlin 解决方案转换回 Java 可能会产生如下结果:
okhttp3.Response raw = httpResponse.raw();
if (raw != null) {
Handshake handshake = raw.handshake();
if (handshake != null) {
List<Certificate> certificates = handshake.peerCertificates();
if (certificates != null) {
for (Certificate certificate : certificates) {
Log.d(TAG, certificate.toString());
}
}
}
}
两种解决方案都可以正常工作,前提handshake()
是握手成功时不为空。
鉴于这是对失败握手的调查,需要进一步的步骤来“信任所有证书”(仅限 NB 调试版本!)。
这已被多次记录 - 这是一个这样的版本:
推荐阅读
- authentication - 如何使用 RxDB 处理 JWT 身份验证?
- r - 如何使用实际的 e 预测值计算 r 中的 MAPE?
- c++ - Android Studio:添加新的 .cpp/.h 文件时如何自动更新 CmakeLists.txt 文件
- python - 高损失验证
- scala - Scala中上界优于子类型的优势
- android - PDF file not opening in release version of android in flutter
- android - 物体落入android
- r - 在 github 存储库的 R 项目中,Anaconda R 环境无法访问库/包
- python - 如何在 pycharm 2019 IDE 中创建散点图
- mongodb - 如何在 PyCharm 中找到 mongoDB 上的查询控制台?