【问题标题】:Android - validating self-signed certificates in addition to normal SSL certificatesAndroid - 除了普通 SSL 证书外,还验证自签名证书
【发布时间】:2012-10-31 06:11:59
【问题描述】:

我有一个通过 SSL 调用 Web 服务的 Android 应用程序。在生产中,我们将拥有由受信任的 CA 签名的普通 SSL 证书。但是,我们需要能够支持自签名证书(由我们自己的 CA 签名)。

我已成功实施建议的接受自签名证书的解决方案,但由于存在中间人攻击的风险,这将不起作用。然后我创建了一个信任管理器来验证证书链实际上是由我们的 CA 签名的。

问题是我必须绕过正常的 SSL 验证 - 应用程序现在只会与安装了我们的自签名证书之一的服务器通信。

我有点迷路了,我用谷歌搜索了很多,但找不到任何东西。我希望找到一种以编程方式将我们的 CA 添加到设备上的信任库的方法,因为这将是处理该问题的侵入性最小的方法。

我想要实现的目标: 1. 对普通 SSL 证书的完全标准支持。 2. 对我们自己的 CA 签名的自签名证书的额外支持。

有什么建议吗?

【问题讨论】:

    标签: java android web-services ssl ssl-certificate


    【解决方案1】:

    您尚未发布任何代码,因此我无法确定您实际做了什么。但是,我假设您只使用自定义的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() 来检查每个信任管理器。如果他们都不信任证书,您可以应用自己的证书检查。如果通过,您可以正常返回。如果没有,只需像其他方式一样抛出CertificateException

    编辑:添加以下有关执行主机名验证等操作的内容。

    您还可以验证证书中的主机名是否符合您的预期。您需要在构造函数中为自定义信任管理器传递有效的主机名,并将其存储在类中。您的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 的内容,因此在这种情况下,您需要做的不仅仅是简单的等号匹配。

    【讨论】:

    • 你可以去myandroidsolutions.blogspot.ro/2012/05/…看看,也许会对你有所帮助。
    • @ziziana 这没用。该页面上的示例允许任何证书,无论是有效、无效、撤销、过期、自签名等。
    • kelnos,谢谢。我没有发布代码,因为该问题与接受自签名证书等无关。您的建议很好,但它没有解决其他需要检查的事情(如主机名验证等)。
    • @Will777 您实际上并没有在您的问题中询问有关主机名验证的任何其他内容,但我也会更新我的答案以反映这一点。
    • @kelnos - 注意。但是,这就是我所说的“对普通 SSL 证书的完全标准支持”——标准验证包括主机名验证。感谢您的所有帮助
    猜你喜欢
    • 2011-12-03
    • 2017-04-18
    • 2015-03-11
    • 1970-01-01
    • 2021-11-10
    • 1970-01-01
    • 2012-11-01
    • 2015-05-23
    • 2019-12-11
    相关资源
    最近更新 更多