如果我在Java程序中使用HttpsURLConnection
并尝试打开以https://
开头的URL,我将收到错误消息:
无法找到所请求目标的有效证书路径
我找到的解决方案是to add the server certificate to the client certificate storage。但是如果我编写一个使用HttpWebRequest
的C#程序,那么我就不必在任何地方添加任何内容。
所以对我而言,它看起来像一个C#客户端“只是工作”而Java客户端只有在用锤子调整后才能工作。
为什么Java客户端需要额外的步骤?我可以以某种方式跳过将证书保存到JVM的客户端存储中吗?
答案 0 :(得分:2)
HttpWebRequest将使用Window自己的证书存储来验证证书,即与IE相同。如果您的IE可以通过将证书或CA路径返回到受信任的根目录来正确验证证书,那么HttpWebRequest应该接受证书确定。
在Java案例中我怀疑添加服务器证书本身是错误的,除非它是自签名的,在这种情况下你将别无选择。您应该将CA路径添加回受信任的根目录 - 您可以将这些证书从Windows的CA存储中提取出来,或者如果需要,可以从根CA的网站下载它们。
答案 1 :(得分:2)
我认为这是因为C#使用与MSIE相同的HTTP客户端,因此它有许多预先安装的SSL证书,包括您使用的SSL证书。 JVM预安装的证书较少。
答案 2 :(得分:1)
默认情况下,Java使用自己的一组信任锚(在默认信任库中,请参阅JSSE Reference Guide)。
如果要使用Windows证书存储区,可以使用Windows-ROOT
keystore作为信任存储区。
答案 3 :(得分:1)
有关此主题的一个很好的信息来源是Oracle网站上的Leveraging Security in the Native Platform Using Java SE 6 Technology和Java Secure Socket Extension (JSSE) Reference Guide。
如果您希望Java使用Windows证书存储来验证证书,那么您可以在启动时指定以下系统属性:
-Djavax.net.ssl.keyStoreType=Windows-MY -Djavax.net.ssl.trustStoreType=Windows-ROOT
如果您只想使用一个连接来使用Windows证书存储来验证证书,则可以修改以下代码以满足您的需求:
KeyStore ks = KeyStore.getInstance("Windows-MY");
ks.load(null, null);
KeyStore ts = KeyStore.getInstance("Windows-ROOT");
ts.load(null, null);
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ts);
KeyManagerFactory kmf = KeyManagerFactory
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, new char[0]);
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
URL url = new URL("https://some.web.site.org");
javax.net.ssl.HttpsURLConnection urlConnection =
(javax.net.ssl.HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(ctx.getSocketFactory());
urlConnection.connect();
try (InputStream in = urlConnection.getInputStream();) {
byte[] chunk = new byte[1024];
for (int len; (len = in.read(chunk)) > -1;) {
System.out.write(chunk, 0, len);
}
} finally {
urlConnection.disconnect();
}