使用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);