java - 忽略过期的ssl证书
你应该建立一个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的安全性目的(而不是仅在有效期限内更灵活)。
此代码完全不起作用。执行tmf.getTrustManagers()时,您将得到“TrustManagerFactory未初始化”的异常。请在未来发布之前测试您的代码。我花了一个多小时试图找出如何解决这个问题。 – AndroidDev 2012-12-06 08:00:59
@AndroidDev,对不起,我假设OP会知道TMF应该像平常一样初始化,但是你可能是对的,这并不明显。 (刚刚编辑。) – Bruno 2012-12-06 10:39:50
总是javax.net.ssl.SSLHandshakeException:连接已关闭peer – 2016-06-14 14:09:37
您必须创建一个将忽略过期证书的自定义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的要点。 – Bruno 2012-01-01 17:21:38
当某些移动设备中的电池被移除时,日期将重置为1980年的旧日期,这会导致您的SSL证书由于失效日期而失败。这可能会导致您的应用程序失败,如果您的应用程序即使使用过期证书仍然可以继续工作至关重要,忽略失效日期非常重要。 – AndroidDev 2012-12-06 06:22:01
@AndroidDev如果您的批评意在解决布鲁诺的评论,那么请注意,接受任何证书和过期的可信证书之间存在巨大差异。此外,由于许多原因,严重用户调整日期。 – 2013-01-10 02:35:09
我写了一个自定义的TrustManager来解决这个问题,你可以在https://gist.github.com/divergentdave/9a68d820e3610513bd4fcdc4ae5f91a1看到它。此TrustManager将有问题的X509Certificate包装在另一个类中,以禁用到期检查,同时保留所有其他验证。 (即匹配主机名,链接到受信任的CA,签名有效等)
不错的例子,我试过了,只是为了查看没有任何** checkValidity **方法被调用。唯一被触发的回调是** getEncoded **和** getPublicKey **。不知道是否与我使用本地密钥库,加载了固定证书的事实有关? – jayeffkay 2017-10-07 13:21:54
@jayeffkay我在本地尝试了这一点,我看到了几种被调用的方法。我看到'checkValidity'被调用,但我不得不设置方法断点而不是行号断点,因为这些方法具有空体。 我不确定固定证书是否会有所作为,但是如果您使用自签名证书作为可能会改变行为的服务器证书(而不是证书)。如果TLS服务器的公共与您的信任存储中的自签名证书的公钥相同,那么其余的检查都是没有意义的。 (没有测试过会发生什么) – dncook 2017-10-08 17:51:57
URL投掷CertificateExpiredException? @Dikobraz – 2015-04-29 09:32:05