使用Java编写SSL检查器
有没有人知道有关用Java编写SSL检查器的任何好的教程,网站和书籍? 我正在尝试做可以在这里找到的东西: http : //www.sslshopper.com/ssl-checker.html 。 我不是要创建自签名证书或使用密钥库。 我希望能够到任何站点确定是否存在有效的SSL证书,确定证书上的主机名是否与输入的命名匹配,并确定此证书何时到期。 我已经搜索了这个主题,但“如何使用Java创建SSL购物者”并没有给我任何东西,而我的其他搜索只给我带来了如何创建自签名证书的链接。 任何帮助将不胜感激。
要获得服务器证书以便手动进行validation,无论其是否有效,最简单的方法是在禁用任何证书validation后通过SSLSocket
进行连接。
创建一个SSLContext
,可以通过以下任何方式:
SSLContext sslContext = SSLContext.getInstance("TLS"); X509TrustManager passthroughTrustManager = new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return null; } }; sslContext.init(null, new TrustManager[] { passthroughTrustManager }, null);
(附注:对于寻求内部使用测试证书的方式的人,我建议建立自己的测试CA而不是禁用检查,以防万一这些虚假检查错误地留在生产代码中,并且因为它使测试更现实。)
创建一个套接字,显式连接并启动握手(因为你真的不会从中读取它):
SSLSocketFactory ssf = sslContext.getSocketFactory(); SSLSocket socket = (SSLSocket) ssf.createSocket( "the.host.name", 443); socket.startHandshake();
获取对等证书链。 第一项是实际的服务器证书。
X509Certificate[] peerCertificates = (X509Certificate[]) socket .getSession().getPeerCertificates();
如果要针对默认信任锚(默认的可信CA证书)进行validation,请根据默认值构建X509TrustManager
(这实际上是上面禁用的passthroughTrustManager
):
// By default on Oracle JRE, algorithm is PKIX TrustManagerFactory tmf = TrustManagerFactory .getInstance(TrustManagerFactory.getDefaultAlgorithm()); // 'null' will initialise the tmf with the default CA certs installed // with the JRE. tmf.init((KeyStore) null); X509TrustManager tm = (X509TrustManager) tmf.getTrustManagers()[0];
现在,检查证书当前是否有效,是否根据RFC 3280对可信锚进行validation以及是否具有正确的扩展。
try { // Assuming RSA key here. tm.checkServerTrusted(peerCertificates, "RSA"); } catch (CertificateException e) { // Here you may check which subclass of CertificateException to know what the error is. }
以上所有都使用了JSSE API 。
或者,如果您想深入了解PKIX的详细信息,可以使用Java Certification Path API (由JSSE使用)。
(如果你只想要有效的证书开始,只需在开始时使用SSLContext sslContext = SSLContext.getDefault()
,创建套接字并进行握手。)
要直接获取服务器证书,您可以使用:
X509Certificate serverCert = peerCertificates[0];
X509Certificate
有许多关于日期和各种扩展的方法。 例如:
Date expirationDate = serverCert.getNotAfter();
主机名validation应遵循RFC 6125 (或至少RFC 2818 )。 简而言之,检查您要连接的主机名是否是主题备用名称(SAN)DNS条目之一。 如果不这样做,请回到检查主机名是否在您的证书的CN RDN中(为此,您需要将主题DN拆分为RDN)。 您可能也对此讨论感兴趣(关于使用IP地址的具体情况) 。
这完全取决于您想要进行多少“手动”validation。 除了API文档之外,还有许多要阅读的规范(至少RFC 5280 / RFC 3280和RFC 6125 / RFC 2818)。
关于Security.SE的这个问题也应引起关注:
- 使用JavavalidationX.509证书时,我应该validation哪些数据?
- 如何表示X.509(SSL)证书的可能用途?
你可以做的是在Apache的HttpClient之上实现你自己的检查器
您应该初始化SSL上下文并覆盖TrustManagers
以执行您想要的任何检查。
主机名validation可以由库自动完成。
例如,如果主机名与证书的信息不匹配,以下将配置SSL套接字处理以引发exception:
SSLSocketFactory sf = new SSLSocketFactory( SSLContext.getInstance("TLS"), SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);