解决:创建OkHttpClient时禁用SSL验证
调用示例
package com.lct.webCollector.xhrrj;
import cn.edu.hfut.dmic.webcollector.model.CrawlDatums;
import cn.edu.hfut.dmic.webcollector.model.Page;
import cn.edu.hfut.dmic.webcollector.plugin.net.OkHttpRequesterSSLIgnore;
import cn.edu.hfut.dmic.webcollector.plugin.ram.RamCrawler;
public class CustomSSLRamCrawler extends RamCrawler {
public static void main(String[] args) throws Exception {
CustomSSLRamCrawler crawler = new CustomSSLRamCrawler();
crawler.setRequester(new OkHttpRequesterSSLIgnore());
crawler.addSeed("https://lexji.com");
crawler.start(1);
}
@Override
public void visit(Page page, CrawlDatums crawlDatums) {
// 处理页面内容
String url = page.url();
String html = page.html();
System.out.println("URL: " + url);
System.out.println("HTML长度: " + html.length());
}
}
package cn.edu.hfut.dmic.webcollector.plugin.net;
import okhttp3.OkHttpClient;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.concurrent.TimeUnit;
public class OkHttpRequesterSSLIgnore extends OkHttpRequester{
public OkHttpRequesterSSLIgnore(){
super();
try {
// 创建信任所有证书的TrustManager
final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};
// 创建SSL上下文并配置
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
// 创建OkHttpClient并配置
client = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.sslSocketFactory(sslSocketFactory, (X509TrustManager)trustAllCerts[0])
.hostnameVerifier((hostname, session) -> true) // 关闭主机名验证
.build();
} catch (NoSuchAlgorithmException | KeyManagementException e) {
throw new RuntimeException(e);
}
}
}
用webcollector爬取有些网站时,找不到有效的证书路径?
java 怎么解决“javax.net.ssl.SSLHandshakeException: 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.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1497)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:212)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.kt:379)
at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.kt:337)
at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:209)
at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:226)
at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106)
at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:74)
at okhttp3.internal.connection.RealCall.initExchangeokhttp(RealCall.kt:255)atokhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)atokhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)atokhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)atokhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)atokhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)atokhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)atokhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)atokhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)atokhttp3.internal.connection.RealCall.getResponseWithInterceptorChainokhttp(RealCall.kt:255)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChainokhttp(RealCall.kt:255)atokhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)atokhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)atokhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)atokhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)atokhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)atokhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)atokhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)atokhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)atokhttp3.internal.connection.RealCall.getResponseWithInterceptorChainokhttp(RealCall.kt:201)
at okhttp3.internal.connection.RealCall.execute(RealCall.kt:154)
at cn.edu.hfut.dmic.webcollector.plugin.net.OkHttpRequester.getResponse(OkHttpRequester.java:94)
at cn.edu.hfut.dmic.webcollector.crawler.AutoParseCrawler.execute(AutoParseCrawler.java:87)
at cn.edu.hfut.dmic.webcollector.fetcher.Fetcher$FetcherThread.run(Fetcher.java:245)
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:387)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1479)
… 27 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:145)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:131)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
… 33 more”
keytool -import -trustcacerts -keystore “C:\Program Files\Java\jdk1.8.0_51\jre\lib\security\cacerts” -storepass changeit -noprompt -alias server_cert -file “D:\360极速浏览器X下载\server.crt”
javax.net.ssl.SSLHandshakeException
表示 Java 应用程序无法验证目标服务器的 SSL/TLS 证书,这是因为目标服务器的证书不被信任。以下是几种常见的解决方案:
1. 确认服务器证书的可信性
- 检查目标服务器的 SSL 证书是否有效(未过期、未吊销、可信的根证书颁发)。
- 使用浏览器访问目标服务器(例如
https://example.com
),查看是否存在证书错误。 - 如果服务器使用自签名证书或未被信任的证书,则需要将其添加到 Java 的信任库。
2. 将证书添加到 Java 信任库
如果目标服务器的证书未被默认信任,可以手动将其添加到 Java 信任库:
步骤:
-
获取目标服务器的证书
- 使用以下命令获取证书并保存为
.crt
文件:echo | openssl s_client -connect example.com:443 | openssl x509 > server.crt
- 使用以下命令获取证书并保存为
-
将证书导入 Java 信任库
- 使用
keytool
将证书导入:keytool -import -trustcacerts -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit -noprompt -alias server_cert -file server.crt
- 注意:
$JAVA_HOME
是你的 Java 安装目录。changeit
是 Java 默认的信任库密码。
- 使用
-
重启你的 Java 应用程序。
3. 使用自定义的 TrustManager
忽略证书验证(仅限测试)
在测试环境中,如果证书验证失败且无法修改信任库,可以通过自定义 TrustManager
忽略 SSL 验证。
示例代码:
import javax.net.ssl.*;
import java.security.cert.X509Certificate;
public class SSLUtil {
public static void disableSSLVerification() {
try {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}
};
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用方式:
在你的应用程序启动时调用:
SSLUtil.disableSSLVerification();
警告:仅限于开发或调试阶段,切勿在生产环境使用!
4. 升级 Java 或 OkHttp 版本
如果使用的是旧版本的 Java 或 OkHttp,可能会缺乏对某些新型证书的支持。建议:
- 升级到最新的 Java 版本。
- 确保 OkHttp 和其依赖(如
okhttp-tls
)为最新版本。
5. 使用正确的 CA 证书
如果目标服务器使用特定的 CA 证书链,你可能需要在 Java 应用中明确指定。
示例:
OkHttpClient client = new OkHttpClient.Builder()
.sslSocketFactory(mySslSocketFactory, myTrustManager)
.build();
你需要实现自定义的 TrustManager
来加载正确的 CA 证书。
总结
- 推荐的解决方法: 在生产环境中,建议配置正确的信任库,并确保目标服务器的证书有效。
- 开发环境: 如果无法解决证书问题,可以使用自定义
TrustManager
暂时绕过验证。