Java HTTPS 连接与 SSL 证书错误
Java HTTPS connection with SSL certificate Error
我正在尝试在 Apache 服务器上使用通过 StartSSL.com 获得的 SSL 证书。与浏览器的连接很好,但是当我尝试使用 Java 应用程序时,我得到了这个异常:
Exception in thread "main" 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
我不明白可能是什么问题,因为在浏览器中,我得到了带有绿色标签的 SSL。
问题是您的 Java 不信任证书。您必须将其导入到 java 的 truststore
。
# Copy the certificate into the directory Java_home\Jre\Lib\Security
# Change your directory to Java_home\Jre\Lib\Security>
# Import the certificate to a trust store.
# Here's the import command:
keytool -import -alias ca -file somecert.cer -keystore cacerts -storepass changeit [Return]
Trust this certificate: [Yes]
changeit 是默认信任库密码。
对于导入到信任库中的每个证书,您都必须提供一个新别名。
导入方法引用自Here
据我了解,这与 Java 证书密钥库有关。 java 不接受您的证书。这是 link 如何将您的证书添加到 Java 受信任的证书密钥库:
https://docs.oracle.com/javase/tutorial/security/toolsign/rstep2.html
SO 上已经有一些这样的问题(比如这个:PKIX path building failed: unable to find valid certification path to requested target)。
对此通常的回答是您的 java 客户端没有完成证书链所需的证书。
如果您需要适当的证书验证,那么您必须找出证书链中断的位置。如果您不这样做(因为这是概念验证或开发沙箱或其他),那么您可以通过将证书添加到您与客户端一起使用的信任库来轻松解决此问题。
编辑:
至于为什么您的浏览器接受这个,很可能是您的浏览器在链中有您需要的证书,或者您不经意地告诉浏览器信任该证书,即使它也无法验证证书。
此消息是由于:
- JRE 没有将根 CA 作为其密钥库中的受信任条目。
- 服务器没有发送正确的链。
但是,2 在您的情况下无效,因为浏览器能够构建链并验证证书。
因此您需要获取根 CA 并将其作为可信条目放入 JRE 密钥库中。有很多资源记录 "how"。其中之一是:
https://access.redhat.com/documentation/en-US/Fuse_Message_Broker/5.3/html/Security_Guide/files/i379776.html
编辑 1:由于您想共享 java 应用程序,我们值得努力从 CA 获得证书,该 CA 的根已在 Java 的信任库中得到信任您的应用支持的版本。
我推荐使用 http-request 建立在 apache http api.
import org.junit.Test;
import static org.apache.http.HttpHeaders.ACCEPT;
import static org.apache.http.HttpStatus.SC_OK;
import static org.apache.http.entity.ContentType.APPLICATION_XML;
import static org.junit.Assert.assertEquals;
public class HttpRequestSSLTest {
private final HttpRequest<?> httpRequest = HttpRequestBuilder.createGet("https://mms.nw.ru/")
.trustAllCertificates()
.trustAllHosts()
.addDefaultHeader(ACCEPT, APPLICATION_XML.getMimeType())
.build();
@Test
public final void ignoreSSLAndHostsTest() throws Exception {
assertEquals(SC_OK, httpRequest.execute().getStatusCode());
}
}
我正在尝试在 Apache 服务器上使用通过 StartSSL.com 获得的 SSL 证书。与浏览器的连接很好,但是当我尝试使用 Java 应用程序时,我得到了这个异常:
Exception in thread "main" 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
我不明白可能是什么问题,因为在浏览器中,我得到了带有绿色标签的 SSL。
问题是您的 Java 不信任证书。您必须将其导入到 java 的 truststore
。
# Copy the certificate into the directory Java_home\Jre\Lib\Security
# Change your directory to Java_home\Jre\Lib\Security>
# Import the certificate to a trust store.
# Here's the import command:
keytool -import -alias ca -file somecert.cer -keystore cacerts -storepass changeit [Return]
Trust this certificate: [Yes]
changeit 是默认信任库密码。
对于导入到信任库中的每个证书,您都必须提供一个新别名。
导入方法引用自Here
据我了解,这与 Java 证书密钥库有关。 java 不接受您的证书。这是 link 如何将您的证书添加到 Java 受信任的证书密钥库: https://docs.oracle.com/javase/tutorial/security/toolsign/rstep2.html
SO 上已经有一些这样的问题(比如这个:PKIX path building failed: unable to find valid certification path to requested target)。
对此通常的回答是您的 java 客户端没有完成证书链所需的证书。
如果您需要适当的证书验证,那么您必须找出证书链中断的位置。如果您不这样做(因为这是概念验证或开发沙箱或其他),那么您可以通过将证书添加到您与客户端一起使用的信任库来轻松解决此问题。
编辑:
至于为什么您的浏览器接受这个,很可能是您的浏览器在链中有您需要的证书,或者您不经意地告诉浏览器信任该证书,即使它也无法验证证书。
此消息是由于:
- JRE 没有将根 CA 作为其密钥库中的受信任条目。
- 服务器没有发送正确的链。
但是,2 在您的情况下无效,因为浏览器能够构建链并验证证书。
因此您需要获取根 CA 并将其作为可信条目放入 JRE 密钥库中。有很多资源记录 "how"。其中之一是: https://access.redhat.com/documentation/en-US/Fuse_Message_Broker/5.3/html/Security_Guide/files/i379776.html
编辑 1:由于您想共享 java 应用程序,我们值得努力从 CA 获得证书,该 CA 的根已在 Java 的信任库中得到信任您的应用支持的版本。
我推荐使用 http-request 建立在 apache http api.
import org.junit.Test;
import static org.apache.http.HttpHeaders.ACCEPT;
import static org.apache.http.HttpStatus.SC_OK;
import static org.apache.http.entity.ContentType.APPLICATION_XML;
import static org.junit.Assert.assertEquals;
public class HttpRequestSSLTest {
private final HttpRequest<?> httpRequest = HttpRequestBuilder.createGet("https://mms.nw.ru/")
.trustAllCertificates()
.trustAllHosts()
.addDefaultHeader(ACCEPT, APPLICATION_XML.getMimeType())
.build();
@Test
public final void ignoreSSLAndHostsTest() throws Exception {
assertEquals(SC_OK, httpRequest.execute().getStatusCode());
}
}