Android - 获取自签名服务器证书并添加到受信任的密钥库

时间:2016-10-24 08:23:54

标签: android ssl okhttp

我的Android应用程序连接到用户提供的 URL 。如果是HTTPS连接,如果服务器的证书是由Android的TrustManager中已经存在的CA颁发的,那么一切都很好。

但是如果服务器使用自签名证书,我如何获得该证书并在第一次连接时将其存储在TrustManager中?

我正在使用OkHttp库来执行网络任务。我目前的解决方案迫使我在开发期间在应用程序的raw文件夹中添加证书,但这不适用于上述场景。我目前使用的代码如下:

private KeyStore readKeyStore() throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());

    String password = "testPass";

    InputStream is = null;

    try {
        is = activity.getApplicationContext().getResources().openRawResource(R.raw.server_key);
        ks.load(is, password.toCharArray());
    } finally {
        if (is != null)
            is.close();
    }

    return ks;
}

private OkHttpClient getOkHttpClient() throws CertificateException, IOException, KeyManagementException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {

    SSLContext sslContext = SSLContext.getInstance("SSL");
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

    trustManagerFactory.init(readKeyStore());
    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    keyManagerFactory.init(readKeyStore(), "testPass".toCharArray());

    sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());

    return new OkHttpClient().setSslSocketFactory(sslContext.getSocketFactory());
}

2 个答案:

答案 0 :(得分:4)

简单的解决方案

以下是信任管理器回调的一些代码示例:https://stackoverflow.com/a/25992879/2657100。从回调中,您可以存储自签名证书,也可以立即接受它们。 但你不应该这样做。通过接受自签名证书,您可能会连接到虚假或恶意服务器,这些服务器可以窃取个人数据,安装恶意软件并执行其他令人讨厌的事情。

优秀的解决方案

如果服务器提供了您(开发人员)在编译时信任的自签名证书,则可以将证书捆绑到应用程序中,就像您已经在做的那样。如果服务器具有CA签名证书会好得多,但如果您确实需要连接到提供自签名证书的服务器,这将(必须)这样做。

更好的解决方案

永远不要在运行时接受自签名证书。如果您希望允许用户连接到这些类型的服务器,您可以在接受自签名证书之前显示一条警告消息,如“自担风险”。

答案 1 :(得分:1)

您不应该在第一次连接时添加它。理想情况下,他们应该付钱才能获得由CA签署的适当证书。

但即使这样,您也可能会发现已安装的Java版本不支持受欢迎的新CA,例如Let's Encrypt。

在这些情况下,您可以使用keytool为JVM手动添加单个证书或新CA,也可以通过标准Android机制加载。

或者您可以将其与应用捆绑在一起。此示例代码显示了如何使用Merged TrustStore https://github.com/yschimke/oksocial/blob/master/src/main/java/com/baulsupp/oksocial/security/CertificateUtils.java

加载现有系统证书之外的捆绑证书