Android - 验证自签名证书和普通SSL证书

3
我有一个Android应用程序,通过SSL调用Web服务。在生产中,我们将拥有由受信任的CA签名的普通SSL证书。但是,我们需要支持自签名证书(由我们自己的CA签名)。
我已经成功实现了接受自签名证书的建议解决方案,但由于中间人攻击的风险,这种方式并不可行。然后,我创建了一个TrustManager来验证证书链是否确实是由我们的CA签名的。
问题是,我必须绕过正常的SSL验证——现在应用程序只会与安装有我们自签名证书之一的服务器通信。
我有点迷失,我已经进行了广泛的谷歌搜索,但找不到任何东西。我希望找到一种编程方式将我们的CA添加到设备上的信任存储库中,因为这将是处理问题最不侵入性的方法。
我的目标: 1. 对普通SSL证书提供完全标准的支持。 2. 支持通过我们自己的CA签名的自签名证书。
请问有什么建议吗?
1个回答

2

你没有发布任何代码,所以我不能确定你实际做了什么。不过,我假设你正在使用自定义的X509TrustManager子类设置SSLContext。这很好,但是你可以让你的自定义信任管理器实现同时链接到内置的信任管理器。你可以在设置信任管理器的同时实现这一点;以下代码应该能够正常工作:

private List<X509TrustManager> trustManagers = new ArrayList<X509TrustManager>();

public MyCustomTrustManager() {
    TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmFactory.init((KeyStore)null);

    for (TrustManager tm : tmFactory.getTrustManagers()) {
        if (tm instanceof X509TrustManager)
            trustManagers.add((X509TrustManager)tm);
    }
}

所以你的自定义信任管理器现在有了所有内置信任管理器的列表。在你重写的checkServerTrusted()中,你需要循环遍历内置信任管理器,并依次调用checkServerTrusted()检查每一个。如果它们都不信任证书,你可以应用自己的证书检查。如果通过了,你可以正常返回。如果没有通过,就像通常一样抛出。
编辑:添加以下内容关于如何执行主机名验证。
你还可以验证证书中的主机名是否与你期望的一致。你需要在你的自定义信任管理器的构造函数中传入有效的主机名并将其存储在类中。你的checkServerTrusted()方法将被传递一个X509Certificate数组。许多“链”将只包含一个证书,但其他链将会有好几个,这取决于cA如何签署你的证书。无论哪种方式,数组中的第一个证书应该是你想要比较的“你的”证书。
在使用信任管理器检查基本证书有效性之后,你将需要执行以下操作:
Principal subjectDN = chain[0].getSubjectDN();
String subjectCN = parseDN(subjectDN.getName(), "CN");
if (this.allowedCN.equals(subjectCN)) {
    // certificate is good
}

parseDN() 的实现由您完成。 subjectDN.getName() 将返回逗号分隔的键值对列表(由=分隔),例如 C=US,ST=California,L=Mountain View,O=Google Inc,CN=www.google.com。 您需要获取 CN(“通用名称”)值以进行主机名比较。 请注意,如果您有通配符证书,则会列出类似于 *.example.com 的内容,因此在这种情况下,您需要进行更复杂的匹配。


1
@ziziana 这并不有用。该页面上的示例允许任何证书,无论是有效的、无效的、已吊销的、过期的、自签名的还是其他类型的证书。 - kelnos
嗨,@kelnos。我正在尝试将我的服务器的自签名证书添加到TrustManager中,但在像你上面提到的"checkServerTrusted()"处遇到了一个异常。但你还提到了如果没有人信任证书,你可以应用自己的证书检查方法,你能指导我如何实现吗? - Ankit
@Ankit 抱歉,我不知道。 - kelnos
嗨@kelnos,感谢您的回复,我已经完成了那部分,实际上服务器自签名证书存在问题。他们也是第一次实施。我想建议其他人,如果您像我一样遇到任何问题,请首先确保服务器端证书在其端正确创建和配置,然后寻找解决方案。 - Ankit
我已经创建了TrustManagerFactory,但是如何使用它呢?它没有提供任何像validate(cert, ca_cert)这样的方法。@Will777 - AndroidDev
显示剩余17条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接