如何使用Java代码读取无效SSL证书的详细信息?
问题原因
报错是HTTPS握手阶段的默认证书校验逻辑拦截导致的:
- Java内置的X509信任管理器默认只会信任JDK根证书库中收录的CA机构颁发的证书,站点证书在信任链内才会完成握手,继续后续操作
- 你测试的
https://self-signed.badssl.com/使用的是自签名证书,没有被JDK内置根证书库收录,所以握手直接中断,还没到获取证书的步骤就抛出了异常;而谷歌的证书由正规CA机构颁发,属于信任链内的证书,所以可以正常读取信息
解决方案
你需要临时禁用SSL证书校验和主机名校验,让握手正常完成后就可以读取站点的证书信息,修改后的完整代码如下:
package com.company; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.net.URL; import java.security.SecureRandom; import java.security.cert.Certificate; import java.security.cert.X509Certificate; public class Main { public static void main(String[] args) throws Exception { // 读取无效证书前先禁用校验逻辑 disableSslValidation(); certInformation("https://self-signed.badssl.com/"); } // 禁用SSL证书校验和主机名校验的工具方法 private static void disableSslValidation() throws Exception { // 构造信任所有证书的信任管理器 TrustManager[] trustAllCerts = new TrustManager[]{ new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } public void checkClientTrusted(X509Certificate[] certs, String authType) { } public void checkServerTrusted(X509Certificate[] certs, String authType) { } } }; // 替换默认的SSL上下文 SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); // 同时禁用主机名校验,避免域名和证书不匹配导致的报错 HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true); } public static void certInformation(String aURL) throws Exception{ URL destinationURL = new URL(aURL); HttpsURLConnection conn = (HttpsURLConnection) destinationURL.openConnection(); conn.connect(); Certificate[] certs = conn.getServerCertificates(); for (Certificate cert : certs) { System.out.println("Certificate is: " + cert); if(cert instanceof X509Certificate) { X509Certificate x = (X509Certificate ) cert; System.out.println("证书颁发者:" + x.getIssuerDN()); System.out.println("证书主体:" + x.getSubjectDN()); System.out.println("证书有效期起始:" + x.getNotBefore()); System.out.println("证书有效期截止:" + x.getNotAfter()); } } } }
注意:该禁用校验的方案仅适用于本地测试读取无效证书的场景,禁止在生产环境使用,会导致HTTPS传输失去加密安全性,容易被中间人攻击。
内容的提问来源于stack exchange,提问作者Anand Somani
相关产品推荐
相关产品推荐

