我要添加到我们的大型 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 应用程序以接受自签名证书的首选方法、标准方法或最佳方法是什么?我能完成上面提到的所有目标吗? 还是我不得不妥协?是否有涉及文件、目录和配置设置以及从小到无代码的选项?