【问题标题】:Public Key pinning with X509TrustManagerExtensions checkServerTrusted使用 X509TrustManagerExtensions checkServerTrusted 固定公钥
【发布时间】:2016-12-16 16:40:36
【问题描述】:

用于 HTTPS TLS 连接的公钥固定。

低于 17 的 Android API 存在一个问题,它会在公钥固定的情况下启用 MITM(中间人)攻击。这已在下面的链接中解释。

https://www.cigital.com/blog/ineffective-certificate-pinning-implementations/

所以在 Android 最小 sdk 低于 17,即 Android 版本 4.2 以下,我们需要使用只有服务器根证书的 Android Keystore 初始化 X509TrustManager而不是默认的 keystore ; 这将在设备中安装所有证书)。这有助于在执行公钥固定之前清理从服务器接收到的叶证书。

从 Android API 17 开始,Android 引入了 X509TrustManagerExtensions,它在操作系统级别执行此根清理。

https://developer.android.com/reference/android/net/http/X509TrustManagerExtensions.html

我的问题:

如果有人能提供一个示例,说明如何实现 X509TrustManagerExtensions 提供的以下方法以进行根目录清理,我将非常高兴。

List<X509Certificate> checkServerTrusted (X509Certificate[] chain, 
                String authType, 
                String host)

我对以下内容感到困惑。

  1. host;它应该是域 URL 吗?有 https 还是没有?还是应该是完整的 url(域 + 相对路径)

  2. 如何创建X509TrustManagerExtensions 的瞬间? X509TrustManagerExtensions 的构造函数将X509TrustManager 作为输入。我们是否使用 android 默认密钥库创建此 X509TrustManager?

代码 sn-p(不工作):

   TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
   tmf.init(KeyStore.getInstance(KeyStore.getDefaultType()));

   for (TrustManager trustManager : tmf.getTrustManagers()) {
       X509TrustManagerExtensions tme = new X509TrustManagerExtensions((X509TrustManager) trustManager);
       tme.checkServerTrusted(chain, authType, <<String https://www.example.com>>);
   }

例外: 找不到证书路径的信任锚

可能的安全风险: 使用KeyStore.getDefaultType()

任何帮助将不胜感激。

【问题讨论】:

  • 您是否有不能使用 >= API 17 的原因?
  • 'X509TrustManagerExtensions' 仅在 API 17 及更高版本中存在。

标签: android x509 tls1.2 trustmanager public-key-pinning


【解决方案1】:

首先,您需要使用TrustManagerFactory 获取信任管理器。初始化时,您传入 null 以使其使用默认的Keystore,它将返回默认的信任管理器。然后,您可以使用第一个 X509TrustManager 创建 X509TrustManagerExtensions

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
        TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);

// Find first X509TrustManager in the TrustManagerFactory
X509TrustManager x509TrustManager = null;
for (TrustManager trustManager : trustManagerFactory.getTrustManagers()) {
    if (trustManager instanceof X509TrustManager) {
        x509TrustManager = (X509TrustManager) trustManager;
        break;
    }
}

X509TrustManagerExtensions x509TrustManagerExtensions = 
        new X509TrustManagerExtensions(trustManager());

然后执行这个我已经成功使用的主机只是域部分:

List<X509Certificate> trustedCerts = x509TrustManagerExtensions
        .checkServerTrusted(untrustedCerts, "RSA", "appmattus.com");

对于那些使用HttpUrlConnection 的人,不受信任的证书是通过以下方式确定的:

Certificate[] serverCerts = ((HttpsUrlConnection)conn).getServerCertificates();
X509Certificate[] untrustedCerts = Arrays.copyOf(serverCerts, 
        serverCerts.length, 
        X509Certificate[].class);

如果您使用的是 OkHttp,那么您可以使用已更新的内置 CertificatePinner 来解决该文章中提到的问题。

【讨论】:

  • 什么是trustManager()方法?
猜你喜欢
  • 1970-01-01
  • 2015-01-22
  • 2017-12-17
  • 2019-10-03
  • 1970-01-01
  • 2017-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多