【发布时间】:2012-01-31 09:56:02
【问题描述】:
URL myUrl = new URL("https://www.....");
网站的 SSL 证书已过期。如何避免它并使 URL() 工作?
【问题讨论】:
-
url 会抛出 CertificateExpiredException 吗? @Dikobraz
URL myUrl = new URL("https://www.....");
网站的 SSL 证书已过期。如何避免它并使 URL() 工作?
【问题讨论】:
您应该构建一个 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 的安全目的(而不是在到期日更灵活一点)。
【讨论】:
您必须创建一个将忽略过期证书的自定义 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 的意义。
我写了一个自定义的 TrustManager 来解决这个问题,你可以在https://gist.github.com/divergentdave/9a68d820e3610513bd4fcdc4ae5f91a1 看到它。此 TrustManager 将有问题的 X509Certificate 包装在另一个类中以禁用过期检查,同时保留所有其他验证。 (即匹配主机名、链接到受信任的 CA、签名有效等)
【讨论】:
checkValidity 被调用,但我必须设置方法断点而不是行号断点,因为这些方法的主体是空的。我不确定固定证书是否会有所作为,但如果您使用自签名证书作为服务器的证书(不是叶证书),可能会改变行为。如果 TLS 服务器的公共密钥与您的信任库中自签名证书的公共密钥相同,则其余检查没有实际意义。 (尚未测试会发生什么)