0

我有一个用 Java 编写的 RESTful 客户端,用于使用 SSL 的 Web 服务。该应用程序已经运行了好几个星期。突然之间,所有与 Web 服务进行交易的尝试都会导致以下异常:

sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
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 com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1699)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:241)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:235)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1206)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:136)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:529)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:893)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1165)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1149)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1172)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:234)
at com.MSCA.ESP.WebApp.ABSManager.getFacilityMetrics(ABSManager.java:1000)
....

我发现的关于类似困难的信息,比如这个,似乎表明我需要在我的客户端环境中使用由/用于 Web 服务的证书做一些事情。但是,我继续能够在 Firefox 中使用 RESTclient 执行在我的 Java 客户端中失败的相同事务,并且据我所知,我从未向 RESTclient 提供与该服务相关的任何类型的证书。

这个应用程序的背景故事是 Web 服务最初是基于 SOAP 协议的,并且最近更改为 REST,这增加了另一个级别的复杂性和混乱,至少从我的角度来看,尽管这可能是其他人的线索至于我的问题可能是什么。最重要的是,我记得几年前第一次开发应用程序时处理 SSL 的唯一一件事是我必须向其中添加以下代码:

static
{
    Security.addProvider( new com.sun.net.ssl.internal.ssl.Provider() );
    System.setProperty( "java.protocol.handler.pkgs", "com.sun.net.ssl.internal.www.protocol" );
    System.setProperty( "javax.net.ssl.trustStore", "./Resources/client.keystore" );
}

client.keystore 文件最初是随 SOAP 接口的示例客户端代码一起提供的。一旦服务切换到 REST,我就保留了这段代码和 client.keystore 文件,因为它似乎没有引起问题,即使似乎没有向严格编写 RESTful 客户端的开发人员提供 client.keystore对于新服务。我今天向 Web 服务提供商提交了一个支持请求,询问可能需要更新 client.keystore。我的困难似乎并没有与他们敲响警钟,所以我想也许我在那里叫错了树。

我不知道我是否在这里提供了足够的信息让任何人给我一个完整的答案,但在这一点上,我很乐意只追求一个特定的向量。到目前为止,我似乎在兜圈子。最后,我不知道这是否重要,但我的应用程序在 Windows Server 2003 标准版上的 Glassfish 3.1.1 下运行。

4

1 回答 1

0

在网络安全的虚拟速成课程之后,我终于推测我的应用程序环境中的根证书需要更新。我找到了一个名为InstallCert.java的实用程序,它将确定特定主机所需的根证书并将它们写入文件。我用它来创建这样一个文件,也称为truststore,并将其重命名为“cacerts.jks”,这是 Glassfish (3.1.1) 用于信任库的文件名。我将它复制到 Glassfish 环境中的两个 cacerts.jks 副本(在/glassfish3/glassfish/lib/templates和中找到/glassfish3/glassfish/domains/domain1/config),重新启动 Glassfish 实例,一切都很好。

一些帮助我弄清楚这一点的博客条目是更新 Java 的根证书,并且无法找到请求目标的有效证书路径。从我的角度来看,还有几个谜团/问题:

  1. InstallCert.java 生成的信任库似乎包含许多我需要更新根证书的主机未使用的根证书。这些是从哪里来的?它们是在我当前的 Java 安装中已经找到的证书吗?如果是这样,它们在 InstallCert.java 代码中的什么位置写入输出文件?

  2. 如何预见和/或避免这个问题?由于根证书似乎主要通过开发工具和应用程序服务器分发,并且大部分都看不见和想不到,是否有任何方法可以通知您的应用程序所依赖的一个已过时?还是希望我们定期更新生产环境中使用的开发工具和应用服务器,以减少被这种情况刺痛的可能性?

于 2013-11-04T17:31:15.717 回答