使用X509TrustManagerExtensions checkServerTrusted进行公钥固定

时间:2016-08-10 10:35:19

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

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

Android API(17岁以下)存在问题,导致MITM(中间人)攻击导致公钥锁定。这已在下面的链接中解释。

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

因此,在Android最低sdk低于17,即低于Android 4.2版本时,我们需要使用仅具有服务器根证书(而非默认密钥库)的Android密钥库初始化 X509TrustManager ;将在设备中安装所有证书)。这有助于在执行公钥锁定之前清除从服务器接收的叶证书。

从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;应该是域名网址吗?用https还是不用?或者它应该是完整的URL(域+相对路径)

  2. 如何创建X509TrustManagerExtensions的即时消息? X509TrustManagerExtensions的构造函数将X509TrustManager作为输入。我们用android默认密钥库创建这个X509TrustManager吗?

  3. 代码段(不工作):

       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()

    非常感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

首先,您需要使用TrustManagerFactory来掌握信任管理员。在初始化时,您传入null以使其使用默认的Keystore,它将返回默认的信任管理器。这样,您就可以使用第一个X509TrustManagerExtensions创建X509TrustManager

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来修复该文章中提到的问题。