如何在 Java 中以编程方式检查 SSL 证书到期日期
Posted
技术标签:
【中文标题】如何在 Java 中以编程方式检查 SSL 证书到期日期【英文标题】:how to check SSL certificate expiration date programmatically in Java 【发布时间】:2012-10-19 03:36:50 【问题描述】:我需要从Java网站上的SSL证书中提取到期日期,应该同时支持 受信任和自签名证书,例如: 1.信任 https://github.com 2.自签 https://mms.nw.ru/
我已经复制了一些代码:
import java.net.URL;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class SSLTest
public static void main(String [] args) throws Exception
// configure the SSLContext with a TrustManager
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(new KeyManager[0], new TrustManager[] new DefaultTrustManager(), new SecureRandom());
SSLContext.setDefault(ctx);
URL url = new URL("https://github.com");//https://mms.nw.ru
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setHostnameVerifier(new HostnameVerifier()
@Override
public boolean verify(String arg0, SSLSession arg1)
return true;
);
System.out.println(conn.getResponseCode());
Certificate[] certs = conn.getServerCertificates();
for (Certificate cert :certs)
System.out.println(cert.getType());
System.out.println(cert);
conn.disconnect();
private static class DefaultTrustManager implements X509TrustManager
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException
@Override
public X509Certificate[] getAcceptedIssuers()
return null;
问题是:
如何从证书中解析过期日期,在我的代码中,toString() 确实输出了日期,但是很难解析。
如何确定证书链,例如链3的github证书,我怎么知道从哪个证书获取到期日期?
【问题讨论】:
尽管我要求使用 .NET,但 Google 仍会指向此处,因此我将在 C# 答案中添加 this link。 我必须在 for 循环之前添加conn.connect();
才能使此代码正常工作并停止接收 java.lang.IllegalStateException: connection not yet open
【参考方案1】:
如何从证书中解析过期日期
将其发送至X509Certificate
并调用getNotAfter()
。
如何确定证书链,例如github证书有链
你明白了。这就是Certificate[]
数组,正如它在Javadoc 中所说的那样。
我怎么知道从哪个证书获取到期日期?
阅读Javadoc。 “对等方自己的证书首先是任何证书颁发机构”。
但是我不知道你为什么要这样做。 Java 应该已经为您完成了这一切。
请丢弃不安全且不正确的 TrustManager 实现。处理自签名证书的正确方法是将它们导入客户端信任库。还请扔掉不安全的 HostnameVerifier,并使用默认的或安全的。如果您不希望 HTTPS 安全,为什么还要使用它?
【讨论】:
我的应用程序是一个监控工具,具有监控 SSL 到期日期的功能,以便在到期时通知客户。所以我不在乎HTTPS是否安全,我只关心它什么时候到期。 “Java 应该已经为你做这一切”是什么意思? @Grace 我的意思是如果证书已经过期,它会抛出一个SSLHandshakeException
。很难相信一个简单的日历条目根本不编写任何 Java 代码就无法实现这一目的。
感谢您的快速回复。我可以从 Certificate 转换为 X509Certificate。无论如何,我们的程序旨在自动监控一个证书的到期日期,并在它即将到期时通知管理员。我们的应用程序是一个监控系统,就像 nagios 等一样。就是这样。你确实帮了大忙:)
@Grace 我明白了,玩得开心。【参考方案2】:
确保将 Begin/End 行附加到 PEM 格式,否则 java 无法理解它。
public class CertTest
public static final String cert = "-----BEGIN CERTIFICATE-----\n<CERT_DATA>\n-----END CERTIFICATE-----";
public static void main(String[] args)
try
X509Certificate myCert = (X509Certificate)CertificateFactory
.getInstance("X509")
.generateCertificate(
// string encoded with default charset
new ByteArrayInputStream(cert.getBytes())
);
System.out.println(myCert.getNotAfter());
catch (Exception e)
// TODO Auto-generated catch block
e.printStackTrace();
【讨论】:
问题中没有任何内容表明 Java 不理解证书格式。 这对我帮助很大【参考方案3】:在 Kotlin 方式中,它应该看起来像这样:
fun certInformation(aURL: String)
val destinationURL = URL(aURL)
val conn = destinationURL.openConnection() as HttpsURLConnection
conn.connect()
val certs = conn.serverCertificates
for (cert in certs)
println("Certificate is: $cert")
if (cert is X509Certificate)
println(cert.issuerDN.name)
println(cert.notAfter)
println(cert.notBefore)
【讨论】:
以上是关于如何在 Java 中以编程方式检查 SSL 证书到期日期的主要内容,如果未能解决你的问题,请参考以下文章
如何以编程方式在 couchbase android 中添加 ssl 证书
来自 Java 客户端的 SSL 错误,但在 Firefox 中以 POSTER 形式工作