You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Tomcat9中Java调用Google Web Risk服务遇PKIX证书路径构建失败求助

问题描述

环境与错误

  • 基于Apache HttpClient开发的Java应用,部署在Tomcat 9服务器(无特殊配置),调用Google Web Risk服务时出现SSL握手错误:

PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

已排查内容

  • 确认目标主机https://webrisk.googleapis.com使用的根证书为GTS Root R1
  • 通过以下命令验证本地Zulu 11 JVM信任库中存在该证书:
keytool -list -keystore /Library/Java/JavaVirtualMachines/zulu-11.jdk/Contents/Home/lib/security/cacerts -v
  • 本地测试客户端无此问题,排除证书本身缺失,问题聚焦于应用加载信任库的方式

已尝试的无效方案

  • 下载“GTS Root 1 cert”的.pem文件,通过SSLContext自定义配置编程加载,未成功
  • 显式设置JVM参数指向验证过的cacerts文件,无效:
-Djavax.net.ssl.trustStore=/Library/Java/JavaVirtualMachines/zulu-11.jdk/Contents/Home/lib/security/cacerts
-Djavax.net.ssl.trustStorePassword=changeit

握手日志

DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection request: [route: {s}->https://webrisk.googleapis.com:443][total available: 0; route allocated: 0 of 2; total allocated: 0 of 20]
DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection leased: [id: 3][route: {s}->https://webrisk.googleapis.com:443][total available: 0; route allocated: 1 of 2; total allocated: 1 of 20]
DEBUG org.apache.http.impl.execchain.MainClientExec - Opening connection {s}->https://webrisk.googleapis.com:443
DEBUG org.apache.http.impl.conn.DefaultHttpClientConnectionOperator - Connecting to webrisk.googleapis.com/142.251.142.202:443
DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory - Connecting socket to webrisk.googleapis.com/142.251.142.202:443 with timeout 0
DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory - Enabled protocols: [TLSv1.3, TLSv1.2]
DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory - Enabled cipher suites:[TLS_AES_256_GCM_SHA384, TLS_AES_128_GCM_SHA256, TLS_CHACHA20_POLY1305_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
DEBUG org.apache.http.conn.ssl.SSLConnectionSocketFactory - Starting handshake
DEBUG org.apache.http.impl.conn.DefaultManagedHttpClientConnection - http-outgoing-3: Shutdown connection
DEBUG org.apache.http.impl.execchain.MainClientExec - Connection discarded
DEBUG org.apache.http.impl.conn.PoolingHttpClientConnectionManager - Connection released: [id: 3][route: {s}->https://webrisk.googleapis.com:443][total available: 0; route allocated: 0 of 2; total allocated: 0 of 20]
ERROR com.akamai.csi.pulsar.mitigation.client.GoogleWebRiskRestClient - PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
排查方向与解决方案

1. 确认Tomcat实际使用的JVM路径

本地验证的是Zulu 11的cacerts,但Tomcat运行时可能使用其他JDK/JRE:

  • 检查Tomcat启动脚本(catalina.sh/catalina.bat)中的JAVA_HOME配置,确认路径与Zulu 11一致
  • 添加一个测试Servlet,输出System.getProperty("java.home"),查看运行时JVM的实际路径

2. 检查Tomcat是否覆盖信任库配置

Tomcat的Connector配置可能覆盖JVM默认信任库:

  • 查看conf/server.xml中的<Connector>节点,是否设置了truststoreFile和truststorePass属性
  • 如果存在上述配置,确保对应的信任库包含GTS Root R1证书

3. 验证Apache HttpClient的SSLContext配置

如果代码中自定义了SSLContext但未正确加载系统信任库,会导致默认信任库失效:

  • 检查HttpClient创建代码,确认是否合并了系统默认信任库
  • 正确的配置示例:
SSLContext sslContext = SSLContexts.custom()
        .loadTrustMaterial(TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()))
        .build();
CloseableHttpClient client = HttpClients.custom()
        .setSSLContext(sslContext)
        .build();

4. 确认JVM参数是否传递给Tomcat

设置的-Djavax.net.ssl.trustStore参数可能未被Tomcat接收:

  • 如果通过环境变量设置,确保Tomcat启动脚本引用了该变量
  • 如果是IDE启动Tomcat,检查VM参数是否正确配置在启动项中
  • 添加-Djavax.net.debug=ssl参数启动Tomcat,查看SSL调试日志,确认实际加载的信任库路径

5. 检查证书链完整性

即使根证书存在,可能缺少中间证书导致路径构建失败:

  • 使用openssl s_client -connect webrisk.googleapis.com:443获取完整证书链
  • 对比本地信任库,确认所有中间证书已被包含(或JVM能自动获取)

内容的提问来源于stack exchange,提问作者Tal Amishai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 03:34:56