服务器端解码Play Integrity Token时遇PKIX证书路径构建失败求助
问题描述
解码Play Integrity Token时出现以下异常:
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
相关代码:
DecodeIntegrityTokenRequest decodeRequest = new DecodeIntegrityTokenRequest(); decodeRequest.setIntegrityToken(integrityToken); InputStream stream = Resources.getResource("credentials.json").openStream(); GoogleCredentials credentials = GoogleCredentials.fromStream(stream); HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(credentials); HttpTransport transport = new NetHttpTransport(); GoogleClientRequestInitializer initializer = new PlayIntegrityRequestInitializer(); // <my-project> 是服务账号凭据JSON文件中的项目ID PlayIntegrity.Builder playIntegrity = new PlayIntegrity.Builder( transport, jsonFactory.getDefaultInstance(), requestInitializer).setApplicationName("<my-project>").setGoogleClientRequestInitializer(initializer); PlayIntegrity play = playIntegrity.build(); DecodeIntegrityTokenResponse response = play.v1().decodeIntegrityToken(appId, decodeRequest).execute();
已尝试操作:
- 按Stack Overflow提示尝试安装证书,但不确定目标站点,尝试
playintegrity.googleapis.com/v1/PACKAGE_NAME的证书无效 - 启用SSL调试后日志如下:
javax.net.ssl|DEBUG|2C|XNIO-1 task-4|2023-04-24 16:44:26.860 PDT|Utilities.java:73|the previous server name in SNI (type=host_name (0), value=playintegrity.googleapis.com) was replaced with (type=host_name (0), value=playintegrity.googleapis.com) javax.net.ssl|DEBUG|2C|XNIO-1 task-4|2023-04-24 16:44:26.942 PDT|SSLCipher.java:1850|KeyLimit read side: algorithm = AES/GCM/NOPADDING:KEYUPDATE countdown value = 137438953472 javax.net.ssl|DEBUG|2C|XNIO-1 task-4|2023-04-24 16:44:26.942 PDT|SSLCipher.java:2004|KeyLimit write side: algorithm = AES/GCM/NOPADDING:KEYUPDATE countdown value = 137438953472 javax.net.ssl|ERROR|2C|XNIO-1 task-4|2023-04-24 16:44:26.965 PDT|TransportContext.java:312|Fatal (CERTIFICATE_UNKNOWN): PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target ( "throwable" : { sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
解决方案
1. 确认正确的证书来源
你需要获取playintegrity.googleapis.com根域名的完整证书链,而非带路径的URL。Google API服务的证书由知名CA(如GlobalSign、DigiCert)颁发,若服务器JVM信任库未包含这些根CA,就会出现路径构建失败。
2. 获取并安装完整证书链
步骤1:导出证书链
使用OpenSSL命令导出站点的完整证书链:
openssl s_client -connect playintegrity.googleapis.com:443 -showcerts < /dev/null | sed -n '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/p' > playintegrity_certs.pem
步骤2:导入到JVM信任库
找到JVM安装目录下的cacerts文件(通常在$JAVA_HOME/jre/lib/security/cacerts或$JAVA_HOME/lib/security/cacerts),用keytool命令导入证书:
keytool -importcert -file playintegrity_certs.pem -alias playintegrity -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit
- 默认信任库密码为
changeit,若已修改请使用对应密码 - 导入时提示是否信任证书,输入
yes确认
3. 代码层面替代方案(无需修改系统信任库)
若无法修改服务器JVM信任库,可在代码中指定自定义信任库:
// 加载自定义信任库 File trustStoreFile = new File("path/to/your/truststore.jks"); String trustStorePassword = "your-password"; TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); trustStore.load(new FileInputStream(trustStoreFile), trustStorePassword.toCharArray()); trustManagerFactory.init(trustStore); SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom()); // 使用自定义SSLContext创建NetHttpTransport HttpTransport transport = new NetHttpTransport.Builder() .setSslContext(sslContext) .build(); // 后续代码保持不变...
4. 检查代理或防火墙配置
若服务器处于代理或防火墙后,确认是否拦截了SSL证书验证,或代理使用了自签名证书。这种情况需要将代理证书也导入到信任库中。
内容的提问来源于stack exchange,提问作者rysv
相关产品推荐
相关产品推荐

