2012-01-01 168 views
4
URL myUrl = new URL("https://www....."); 

网站的SSL证书已过期。如何避免它,并使URL()工作?java - 忽略过期的ssl证书

+0

URL投掷CertificateExpiredException? @Dikobraz – 2015-04-29 09:32:05

回答

15

你应该建立一个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()); 

信托经理抛出CertificateException S(详见子类),什么是错用证书。具体说明你想要捕捉/忽略的内容。在你捕获的东西可能被抛出之前,你真正要验证的所有东西都必须被检查,否则你也必须手动验证它。比这更轻松的任何事情(尤其是没有做任何事情,因此不会抛出任何异常)将完全忽略证书验证和验证,这与使用匿名密码套件或忽略验证大致相同。这将破坏使用SSL/TLS的安全性目的(而不是仅在有效期限内更灵活)。

+0

此代码完全不起作用。执行tmf.getTrustManagers()时,您将得到“TrustManagerFactory未初始化”的异常。请在未来发布之前测试您的代码。我花了一个多小时试图找出如何解决这个问题。 – AndroidDev 2012-12-06 08:00:59

+1

@AndroidDev,对不起,我假设OP会知道TMF应该像平常一样初始化,但是你可能是对的,这并不明显。 (刚刚编辑。) – Bruno 2012-12-06 10:39:50

+0

总是javax.net.ssl.SSLHandshakeException:连接已关闭peer – 2016-06-14 14:09:37

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) { 
} 
+2

请避免复制/粘贴/传播完全禁用安全检查的代码,正如'TrustManager'所做的:这首先破坏了使用SSL/TLS的要点。 – Bruno 2012-01-01 17:21:38

+0

当某些移动设备中的电池被移除时,日期将重置为1980年的旧日期,这会导致您的SSL证书由于失效日期而失败。这可能会导致您的应用程序失败,如果您的应用程序即使使用过期证书仍然可以继续工作至关重要,忽略失效日期非常重要。 – AndroidDev 2012-12-06 06:22:01

+0

@AndroidDev如果您的批评意在解决布鲁诺的评论,那么请注意,接受任何证书和过期的可信证书之间存在巨大差异。此外,由于许多原因,严重用户调整日期。 – 2013-01-10 02:35:09

1

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

+0

不错的例子,我试过了,只是为了查看没有任何** checkValidity **方法被调用。唯一被触发的回调是** getEncoded **和** getPublicKey **。不知道是否与我使用本地密钥库,加载了固定证书的事实有关? – jayeffkay 2017-10-07 13:21:54

+0

@jayeffkay我在本地尝试了这一点,我看到了几种被调用的方法。我看到'checkValidity'被调用,但我不得不设置方法断点而不是行号断点,因为这些方法具有空体。 我不确定固定证书是否会有所作为,但是如果您使用自签名证书作为可能会改变行为的服务器证书(而不是证书)。如果TLS服务器的公共与您的信任存储中的自签名证书的公钥相同,那么其余的检查都是没有意义的。 (没有测试过会发生什么) – dncook 2017-10-08 17:51:57