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