如何在特定连接上使用不同的证书?
我正在添加到我们大型Java应用程序中的模块必须与另一家公司的SSL安全网站进行对话。问题是该站点使用自签名证书。我有一个证书副本来验证我没有遇到中间人攻击,我需要将此证书合并到我们的代码中,以便成功连接到服务器。
以下是基本代码:
void sendRequest(String dataPacket) {
String urlStr = "https://host.example.com/";
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setMethod("POST");
conn.setRequestProperty("Content-Length", data.length());
conn.setDoOutput(true);
OutputStreamWriter o = new OutputStreamWriter(conn.getOutputStream());
o.write(data);
o.flush();
}
如果不对自签名证书进行任何额外的处理,这将在conn.getOutputStream()上死亡,但以下情况除外:
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
....
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
....
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
理想情况下,我的代码需要教Java接受这个自签名证书,对于应用程序中的这个位置,而不是其他地方。
我知道我可以将证书导入到 JRE 的证书颁发机构存储区中,这将允许 Java 接受它。如果我能帮忙,这不是我想采取的方法;在我们客户的所有机器上为他们可能不使用的一个模块做似乎非常侵入性;它会影响使用相同JRE的所有其他Java应用程序,我不喜欢这样,即使任何其他Java应用程序访问此站点的几率为零。这也不是一个微不足道的操作:在UNIX上,我必须获得访问权限才能以这种方式修改JRE。
我还看到,我可以创建一个 TrustManager 实例来执行一些自定义检查。看起来我甚至可以创建一个TrustManager,该管理器在所有实例中都委托给真正的TrustManager,除了这个证书。但看起来TrustManager是全局安装的,我想这会影响我们应用程序中的所有其他连接,这对我来说也不是很清楚。
设置 Java 应用程序以接受自签名证书的首选、标准或最佳方法是什么?我能实现上面想到的所有目标吗,还是我必须妥协?是否有涉及文件和目录以及配置设置以及很少甚至没有代码的选项?