错误1:
10:13:47.520 [main] DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory - Starting handshake 10:13:47.523 [main] DEBUG org.apache.http.impl.conn.DefaultManagedHttpClientConnection - http-outgoing-0: Shutdown connection 10:13:47.523 [main] DEBUG org.apache.http.impl.execchain.MainClientExec - Connection discarded 10:13:47.523 [main] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection released: [id: 0][route: {s}->https://223.108.104.37:8180][total available: 0; route allocated: 0 of 2; total allocated: 0 of 20] 10:13:47.524 [main] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection manager is shutting down 10:13:47.524 [main] DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection manager shut down Exception in thread "main" javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate) at sun.security.ssl.HandshakeContext.(HandshakeContext.java:171) at sun.security.ssl.ClientHandshakeContext. (ClientHandshakeContext.java:106) at sun.security.ssl.TransportContext.kickstart(TransportContext.java:245) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:410) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:389) at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:436) at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:384) at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:376) at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393) at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236) at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186) at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89) at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
- SSLHandshakeException 异常:我这边是使用的协议TLSv1版本太低,换一个就行
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( sslcontext, new String[]{"TLSv1.2"}, // 使用 TLSv1.2 协议 null, NoopHostnameVerifier.INSTANCE);
错误2:
sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.ssl.Alert.createSSLException(Alert.java:131) at sun.security.ssl.TransportContext.fatal(TransportContext.java:377) at sun.security.ssl.TransportContext.fatal(TransportContext.java:320) at sun.security.ssl.TransportContext.fatal(TransportContext.java:315) at sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:652) at sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(CertificateMessage.java:471) at sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(CertificateMessage.java:367) at sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:376) at sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:479) at sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:457) at sun.security.ssl.TransportContext.dispatch(TransportContext.java:200) at sun.security.ssl.SSLTransport.decode(SSLTransport.java:155) at sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1320) at sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1233) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:417) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:389) at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:436) at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:384) at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:376) at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393) at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236) at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186) at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89) at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108) at com.waterapidemo.util.HttpPostUtil.sslRequest(HttpPostUtil.java:108) at com.waterapidemo.util.HttpPostUtil.main(HttpPostUtil.java:74) Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:439) at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:306) at sun.security.validator.Validator.validate(Validator.java:271) at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:312) at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:221) at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:128) at sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:636) ... 25 more Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:148)
- JVM默认信任证书不包含该目标网站的SSL证书,导致无法建立有效的信任链接。
keytool -importcert -alias xxx.xxx.xxx.xxx -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit -file xxxxx.cert
解决办法:
1.获取服务器的证书
package com.waterapidemo.util; import java.io.FileOutputStream; import java.io.InputStream; import java.net.Socket; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; public class FetchServerCert { private static final String SERVER_HOST = "xxxxxxxxx"; private static final int SERVER_PORT = xxxx; private static final String CERT_FILE = "X:\\xxx\\server-cert.cer"; public static void main(String[] args) { try { // Step 1: Set up a TrustManager that accepts all certificates 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) { } } }; SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); SSLSocketFactory factory = sslContext.getSocketFactory(); // Step 2: Connect to the server and retrieve the server certificate try (SSLSocket socket = (SSLSocket) factory.createSocket(SERVER_HOST, SERVER_PORT)) { socket.startHandshake(); Certificate[] serverCerts = socket.getSession().getPeerCertificates(); // Step 3: Save the first server certificate to a file try (FileOutputStream fos = new FileOutputStream(CERT_FILE)) { fos.write(serverCerts[0].getEncoded()); } System.out.println("Server certificate saved to " + CERT_FILE); } } catch (Exception e) { e.printStackTrace(); } } }
- 定义一个自定义的 TrustManager,它将接受所有证书
2.将证书导入JVM信任库
package com.waterapidemo.util; import java.io.*; import java.security.KeyStore; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; public class ImportServerCert { private static final String CERT_FILE = "X:\\xxx\\server-cert.cer"; private static final String TRUSTSTORE_PATH = "X:\\xxx\\truststore.jks"; private static final String TRUSTSTORE_PASSWORD = "changeit"; public static void main(String[] args) { try { // Load the server certificate from the file Certificate serverCert = loadCertificate(CERT_FILE); // Create a truststore and add the server certificate to it KeyStore trustStore = createTrustStore(serverCert, TRUSTSTORE_PATH, TRUSTSTORE_PASSWORD); // Save the truststore to a file try (FileOutputStream fos = new FileOutputStream(TRUSTSTORE_PATH)) { trustStore.store(fos, TRUSTSTORE_PASSWORD.toCharArray()); System.out.println("Truststore created and saved to " + TRUSTSTORE_PATH); } } catch (Exception e) { e.printStackTrace(); } } private static Certificate loadCertificate(String certFilePath) throws Exception { CertificateFactory cf = CertificateFactory.getInstance("X.509"); try (FileInputStream fis = new FileInputStream(certFilePath)) { return cf.generateCertificate(fis); } } private static KeyStore createTrustStore(Certificate cert, String trustStorePath, String trustStorePassword) throws Exception { KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); trustStore.load(null, null); // Initialize the empty truststore String alias = "server-cert"; trustStore.setCertificateEntry(alias, cert); return trustStore; } }
3.请求的时候携带好证书就可以了
public static String sslRequest(String url, String params, String token) throws Exception { String results; // Load client certificate KeyStore keyStore = KeyStore.getInstance("xxxx"); try (FileInputStream keyStoreStream = new FileInputStream(PATH)) { keyStore.load(keyStoreStream, PASSWORD.toCharArray()); } // Load truststore containing server certificate KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); try (FileInputStream trustStoreStream = new FileInputStream(TRUSTSTORE_PATH)) { trustStore.load(trustStoreStream, TRUSTSTORE_PASSWORD.toCharArray()); } // Set up SSL context with client certificate and truststore SSLContext sslContext = SSLContexts.custom() .loadKeyMaterial(keyStore, PASSWORD.toCharArray()) .loadTrustMaterial(trustStore, null) .build(); // Create SSL connection factory SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); // Create HTTP client with custom SSL context try (CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build()) { // Create HTTP POST request HttpPost httpPost = new HttpPost(url); httpPost.setHeader("FROM", token); httpPost.setEntity(new StringEntity(params, "UTF-8")); // Execute request try (CloseableHttpResponse response = httpClient.execute(httpPost)) { HttpEntity entity = response.getEntity(); results = EntityUtils.toString(entity, "UTF-8"); EntityUtils.consume(entity); } } return results; }
- 定义一个自定义的 TrustManager,它将接受所有证书
- JVM默认信任证书不包含该目标网站的SSL证书,导致无法建立有效的信任链接。
还没有评论,来说两句吧...