【问题标题】:java - ignore expired ssl certificatejava - 忽略过期的ssl证书
【发布时间】:2012-01-31 09:56:02
【问题描述】:
URL myUrl = new URL("https://www.....");

网站的 SSL 证书已过期。如何避免它并使 URL() 工作?

【问题讨论】:

标签: java android url ssl


【解决方案1】:

您应该构建一个 TrustManager 来包装默认信任管理器,捕获 CertificiateExpiredException 并忽略它。

注意:如this answer 中所述,这是否安全很大程度上取决于实现。特别是,它依赖于在正确检查其他所有内容之后最后完成的日期验证。

按照这些思路应该可以工作:

TrustManagerFactory tmf = TrustManagerFactory.getInstance(
    TrustManagerFactory.getDefaultAlgorithm());
// Initialise the TMF as you normally would, for example:
tmf.init((KeyStore)null); 

TrustManager[] trustManagers = tmf.getTrustManagers();
final X509TrustManager origTrustmanager = (X509TrustManager)trustManagers[0];

TrustManager[] wrappedTrustManagers = new TrustManager[]{
   new X509TrustManager() {
       public java.security.cert.X509Certificate[] getAcceptedIssuers() {
          return origTrustmanager.getAcceptedIssuers();
       }

       public void checkClientTrusted(X509Certificate[] certs, String authType) {
           origTrustmanager.checkClientTrusted(certs, authType);
       }

       public void checkServerTrusted(X509Certificate[] certs, String authType) {
           try {
               origTrustmanager.checkServerTrusted(certs, authType);
           } catch (CertificateExpiredException e) {}
       }
   }
};

SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, wrappedTrustManagers, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

当证书出现问题时,信任管理器会抛出 CertificateExceptions(有关详细信息,请参阅子类)。具体说明您想要捕获/忽略的内容。您真正想要验证的所有内容都必须在您捕获的内容可能被抛出之前进行检查,否则您也必须手动验证它。任何比这更轻松的事情(特别是不做任何事情,因此不抛出任何异常)将完全忽略证书验证和验证,这与使用匿名密码套件或忽略身份验证大致相同。这会破坏使用 SSL/TLS 的安全目的(而不是在到期日更灵活一点)。

【讨论】:

  • 这段代码根本不起作用。执行 tmf.getTrustManagers() 时会出现“TrustManagerFactory 未初始化”异常。请在将来发布之前测试您的代码。我花了一个多小时试图弄清楚如何解决这个问题。
  • @AndroidDev,对不起,我假设 OP 会知道 TMF 应该正常初始化,但你可能是对的,这并不明显。 (刚刚编辑。)
  • 总是 javax.net.ssl.SSLHandshakeException:连接被对等方关闭
  • 请注意,在 ssl 客户端身份验证的情况下,服务器本身可能会检查客户端证书的到期情况。在这种情况下无法治愈:stackoverflow.com/questions/2762080/…
  • @Bruno 我正在使用 Retrofit 进行网络调用,我必须在我的 Android 应用程序中调用这个 TrustManger?
【解决方案2】:

您必须创建一个将忽略过期证书的自定义 X509 验证器。事实上,不会执行任何检查。

代码取自这里:http://exampledepot.com/egs/javax.net.ssl/TrustAll.html

// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[]{
    new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }
        public void checkClientTrusted(
            java.security.cert.X509Certificate[] certs, String authType) {
        }
        public void checkServerTrusted(
            java.security.cert.X509Certificate[] certs, String authType) {
        }
    }
};

// Install the all-trusting trust manager
try {
    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
}

// Now you can access an https URL without having the certificate in the truststore
// It should work with expired certificate as well
try {
    URL myUrl = new URL("https://www.....");
} catch (MalformedURLException e) {
}

【讨论】:

  • 请避免复制/粘贴/传播完全禁用安全检查的代码,就像 TrustManager 所做的那样:这首先破坏了使用 SSL/TLS 的意义。
  • 在某些移动设备中取出电池后,日期会重置为旧日期,例如 1980 年,这将导致您的 SSL 证书因到期日期而失效。这可能会导致您的应用失败,如果您的应用在证书过期后仍能继续运行至关重要,那么忽略过期日期很重要。
  • @AndroidDev 如果您的批评是为了解决布鲁诺的评论,那么请注意,接受任何证书和过时的受信任证书之间存在巨大差异。此外,认真的用户会出于多种原因调整日期。
  • 总是 javax.net.ssl.SSLHandshakeException:连接被对等方关闭
【解决方案3】:

我写了一个自定义的 TrustManager 来解决这个问题,你可以在https://gist.github.com/divergentdave/9a68d820e3610513bd4fcdc4ae5f91a1 看到它。此 TrustManager 将有问题的 X509Certificate 包装在另一个类中以禁用过期检查,同时保留所有其他验证。 (即匹配主机名、链接到受信任的 CA、签名有效等)

【讨论】:

  • 不错的例子,我试过了,只是发现没有调用任何 checkValidity 方法。触发的唯一回调是 getEncodedgetPublicKey。不确定这是否与我使用本地密钥库并加载了固定证书这一事实有关?
  • @jayeffkay 我在本地尝试了这个,我看到有几个方法被调用。我确实看到checkValidity 被调用,但我必须设置方法断点而不是行号断点,因为这些方法的主体是空的。我不确定固定证书是否会有所作为,但如果您使用自签名证书作为服务器的证书(不是叶证书),可能会改变行为。如果 TLS 服务器的公共密钥与您的信任库中自签名证书的公共密钥相同,则其余检查没有实际意义。 (尚未测试会发生什么)
猜你喜欢
  • 1970-01-01
  • 2019-09-02
  • 2022-01-17
  • 2023-03-31
  • 2012-08-17
  • 2011-04-09
  • 1970-01-01
  • 2016-01-28
相关资源
最近更新 更多