我必须访问Https API。它与 Postman 和Android Asynchronous Http Client库一起工作正常。
但是当我在桌面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
javax.servlet.ServletException: 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
com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:420)
com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:558)
com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:733)
javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
我无法使用的桌面代码:
HttpURLConnection con;
String response;
try {
con = (HttpURLConnection) new URL(LOGIN_URL).openConnection();
con.setDoOutput(true);
con.setRequestMethod("GET");
OutputStream os = con.getOutputStream(); //throws error
os.flush();
return "200";
} catch (Exception e) {
e.printStackTrace();
return e.toString();
}
我的Android工作代码:
AsyncHttpClient client = new AsyncHttpClient();
RequestParams rp = new RequestParams();
client.get("LOGIN_URL", rp, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] response) {
return new String(response); //works
}
});
所以,我的问题是:如果可以使其在Android上运行,为什么不能使用 Apache HttpComponents 或 HttpURLConnection 方法?
有没有我可以使用的库,而无需安装任何证书,就像在Android上一样?出于服务器原因,我只想信任没有它的Web服务。
答案 0 :(得分:1)
可能是因为Postman信任您明确表示已信任浏览的证书,但Java不信任。
尝试使用此solution to the SSLHandshakeException:
当您的服务器具有自签名证书时,出现此问题。至 解决方法,您可以将此证书添加到受信任的列表中 JVM的证书。
在this article中 作者介绍了如何从浏览器中获取证书,以及 将其添加到JVM的cacerts文件中。您可以编辑 JAVA_HOME / jre / lib / security / cacerts文件或使用以下命令运行应用程序 -Djavax.net.ssl.trustStore参数。验证您也正在使用哪个JDK / JRE,因为这经常会引起混乱。
另请参阅:How are SSL certificate server names resolved/Can I add alternative names using keytool? 如果遇到java.security.cert.CertificateException:无名称 匹配的本地主机发现异常。
答案 1 :(得分:1)
您需要将根链添加到CA证书文件中,以便Java可以验证自签名证书。
Postman信任您已在浏览器中明确信任的证书。
要更新您的CA certs文件,您需要找到它,因为您可能已安装了JDK,而您要查找的文件很可能位于JDK的JRE文件夹中。 ./jdk1.8/jre/lib/security/cacerts
要将Java添加到您的信任库中,请使用keytool
(如果Java在您的环境路径上),首先运行以下命令,其中example.der是您的证书。我也建议您给它起一个更好的别名。
keytool -import -alias example -keystore /path/to/cacerts -file example.der
系统将提示您输入密码,java的默认值为changeit
,输入密码,并在询问您是否信任证书时输入yes
。
添加证书后,您可以再次使用keytool列出您在密钥库中拥有的所有证书,再次提示您输入密码。
keytool -list -v -keystore /path/to/cacerts
当我运行此命令时,我会得到一个列表。您应该能够找到别名为example
的证书。这是我列表中的第一名。
Alias name: digicertglobalrootca [jdk]
Creation date: 26 Aug. 2016
Entry type: trustedCertEntry
Owner: CN=DigiCert Global Root CA, OU=www.digicert.com, O=DigiCert Inc, C=US
Issuer: CN=DigiCert Global Root CA, OU=www.digicert.com, O=DigiCert Inc, C=US
Serial number: 83be056904246b1a1756ac95991c74a
Valid from: Fri Nov 10 10:00:00 AEST 2006 until: Mon Nov 10 10:00:00 AEST 2031
Certificate fingerprints:
SHA1: A8:98:5D:3A:65:E5:E5:C4:B2:D7:D6:6D:40:C6:DD:2F:B1:9C:54:36
SHA256: 43:48:A0:E9:44:4C:78:CB:26:5E:05:8D:5E:89:44:B4:D8:4F:96:62:BD:26:DB:25:7F:89:34:A4:43:C7:01:61
Signature algorithm name: SHA1withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3
您已更新问题,以包括要忽略证书的信息...
请不要忽略证书错误。相反,应对它们。 忽略证书错误将打开与潜在MITM的连接 攻击。诱人的是,它仅用于测试代码,不会在 生产,但我们都知道截止日期临近时会发生什么: 该代码在测试时没有显示任何错误->我们可以发货 照原样。
现在,我知道您决心要执行此操作-here是一些相关代码。
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
}
// Now you can access an https URL without having the certificate in the truststore
try {
URL url = new URL("https://hostname/index.html");
} catch (MalformedURLException e) {
}